Renamed Xedit -> Xed (avoid name clash with x11-apps's xedit)
This commit is contained in:
209
xed/Makefile.am
Normal file
209
xed/Makefile.am
Normal file
@@ -0,0 +1,209 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
SUBDIRS = dialogs smclient
|
||||
|
||||
bin_PROGRAMS = xed
|
||||
|
||||
noinst_LTLIBRARIES = libxed.la
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(srcdir) \
|
||||
-I$(srcdir)/smclient \
|
||||
$(XED_CFLAGS) \
|
||||
$(MATE_DESKTOP_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(DISABLE_DEPRECATED_CFLAGS) \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\"
|
||||
|
||||
xed_SOURCES = \
|
||||
xed.c
|
||||
|
||||
xed_LDADD = libxed.la $(XED_LIBS) $(EGG_SMCLIENT_LIBS)
|
||||
|
||||
xed_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_]].*"
|
||||
|
||||
libxed_la_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_]].*"
|
||||
|
||||
libxed_la_LIBADD = \
|
||||
dialogs/libdialogs.la \
|
||||
smclient/libeggsmclient.la \
|
||||
$(MATE_DESKTOP_LIBS)
|
||||
|
||||
# XED_LIBS must be the last to ensure correct order on some platforms
|
||||
libxed_la_LIBADD += $(XED_LIBS) -lICE
|
||||
|
||||
BUILT_SOURCES = \
|
||||
xed-enum-types.c \
|
||||
xed-enum-types.h \
|
||||
xed-marshal.c \
|
||||
xed-marshal.h
|
||||
|
||||
|
||||
NOINST_H_FILES = \
|
||||
xed-close-button.h \
|
||||
xed-dirs.h \
|
||||
xed-document-input-stream.h \
|
||||
xed-document-loader.h \
|
||||
xed-document-output-stream.h \
|
||||
xed-document-saver.h \
|
||||
xed-documents-panel.h \
|
||||
xed-gio-document-loader.h \
|
||||
xed-gio-document-saver.h \
|
||||
xed-history-entry.h \
|
||||
xed-io-error-message-area.h \
|
||||
xed-language-manager.h \
|
||||
xed-object-module.h \
|
||||
xed-plugin-info.h \
|
||||
xed-plugin-info-priv.h \
|
||||
xed-plugin-loader.h \
|
||||
xed-plugin-manager.h \
|
||||
xed-plugins-engine.h \
|
||||
xed-prefs-manager-private.h \
|
||||
xed-print-job.h \
|
||||
xed-print-preview.h \
|
||||
xed-session.h \
|
||||
xed-smart-charset-converter.h \
|
||||
xed-style-scheme-manager.h \
|
||||
xed-tab-label.h \
|
||||
xedtextregion.h \
|
||||
xed-ui.h \
|
||||
xed-window-private.h
|
||||
|
||||
INST_H_FILES = \
|
||||
xed-app.h \
|
||||
xed-commands.h \
|
||||
xed-debug.h \
|
||||
xed-document.h \
|
||||
xed-encodings.h \
|
||||
xed-encodings-combo-box.h \
|
||||
xed-file-chooser-dialog.h \
|
||||
xed-help.h \
|
||||
xed-message-bus.h \
|
||||
xed-message-type.h \
|
||||
xed-message.h \
|
||||
xed-notebook.h \
|
||||
xed-panel.h \
|
||||
xed-plugin.h \
|
||||
xed-prefs-manager-app.h \
|
||||
xed-prefs-manager.h \
|
||||
xed-progress-message-area.h \
|
||||
xed-statusbar.h \
|
||||
xed-status-combo-box.h \
|
||||
xed-tab.h \
|
||||
xed-utils.h \
|
||||
xed-view.h \
|
||||
xed-window.h
|
||||
|
||||
if !ENABLE_GVFS_METADATA
|
||||
INST_H_FILES += xed-metadata-manager.h
|
||||
endif
|
||||
|
||||
headerdir = $(prefix)/include/xed
|
||||
|
||||
header_DATA = \
|
||||
$(INST_H_FILES)
|
||||
|
||||
|
||||
libxed_la_SOURCES = \
|
||||
$(BUILT_SOURCES) \
|
||||
$(BACON_FILES) \
|
||||
$(POSIXIO_FILES) \
|
||||
xed-app.c \
|
||||
xed-close-button.c \
|
||||
xed-commands-documents.c \
|
||||
xed-commands-edit.c \
|
||||
xed-commands-file.c \
|
||||
xed-commands-file-print.c \
|
||||
xed-commands-help.c \
|
||||
xed-commands-search.c \
|
||||
xed-commands-view.c \
|
||||
xed-debug.c \
|
||||
xed-dirs.c \
|
||||
xed-document.c \
|
||||
xed-document-input-stream.c \
|
||||
xed-document-loader.c \
|
||||
xed-document-output-stream.c \
|
||||
xed-gio-document-loader.c \
|
||||
xed-document-saver.c \
|
||||
xed-gio-document-saver.c \
|
||||
xed-documents-panel.c \
|
||||
xed-encodings.c \
|
||||
xed-encodings-combo-box.c \
|
||||
xed-file-chooser-dialog.c \
|
||||
xed-help.c \
|
||||
xed-history-entry.c \
|
||||
xed-io-error-message-area.c \
|
||||
xed-language-manager.c \
|
||||
xed-message-bus.c \
|
||||
xed-message-type.c \
|
||||
xed-message.c \
|
||||
xed-object-module.c \
|
||||
xed-notebook.c \
|
||||
xed-panel.c \
|
||||
xed-plugin-info.c \
|
||||
xed-plugin.c \
|
||||
xed-plugin-loader.c \
|
||||
xed-plugin-manager.c \
|
||||
xed-plugins-engine.c \
|
||||
xed-prefs-manager-app.c \
|
||||
xed-prefs-manager.c \
|
||||
xed-prefs-manager-private.h \
|
||||
xed-print-job.c \
|
||||
xed-print-preview.c \
|
||||
xed-progress-message-area.c \
|
||||
xed-session.c \
|
||||
xed-smart-charset-converter.c \
|
||||
xed-statusbar.c \
|
||||
xed-status-combo-box.c \
|
||||
xed-style-scheme-manager.c \
|
||||
xed-tab.c \
|
||||
xed-tab-label.c \
|
||||
xed-utils.c \
|
||||
xed-view.c \
|
||||
xed-window.c \
|
||||
xedtextregion.c \
|
||||
$(NOINST_H_FILES) \
|
||||
$(INST_H_FILES)
|
||||
|
||||
if !ENABLE_GVFS_METADATA
|
||||
libxed_la_SOURCES += xed-metadata-manager.c
|
||||
endif
|
||||
|
||||
xed-enum-types.h: xed-enum-types.h.template $(INST_H_FILES) $(GLIB_MKENUMS)
|
||||
$(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template xed-enum-types.h.template $(INST_H_FILES)) > $@
|
||||
|
||||
xed-enum-types.c: xed-enum-types.c.template $(INST_H_FILES) $(GLIB_MKENUMS)
|
||||
$(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template xed-enum-types.c.template $(INST_H_FILES)) > $@
|
||||
|
||||
xed-marshal.h: xed-marshal.list $(GLIB_GENMARSHAL)
|
||||
$(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=xed_marshal > $@
|
||||
|
||||
xed-marshal.c: xed-marshal.list $(GLIB_GENMARSHAL)
|
||||
$(AM_V_GEN) echo "#include \"xed-marshal.h\"" > $@ && \
|
||||
$(GLIB_GENMARSHAL) $< --body --prefix=xed_marshal >> $@
|
||||
|
||||
uidir = $(datadir)/xed/ui/
|
||||
ui_DATA = \
|
||||
xed-ui.xml \
|
||||
xed-print-preferences.ui
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(ui_DATA) \
|
||||
xed-enum-types.h.template \
|
||||
xed-enum-types.c.template \
|
||||
xed-marshal.list \
|
||||
xed.rc
|
||||
|
||||
CLEANFILES = $(BUILT_SOURCES)
|
||||
|
||||
dist-hook:
|
||||
cd $(distdir); rm -f $(BUILT_SOURCES)
|
||||
|
||||
BACON_DIR=$(srcdir)/../../libbacon/src/
|
||||
BACON_FILES=bacon-message-connection.h bacon-message-connection.c
|
||||
|
||||
regenerate-built-sources:
|
||||
BACONFILES="$(BACON_FILES)" BACONDIR="$(BACON_DIR)" $(top_srcdir)/xed/update-from-bacon.sh
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
396
xed/bacon-message-connection.c
Normal file
396
xed/bacon-message-connection.c
Normal file
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "bacon-message-connection.h"
|
||||
|
||||
#ifndef UNIX_PATH_MAX
|
||||
#define UNIX_PATH_MAX 108
|
||||
#endif
|
||||
|
||||
struct BaconMessageConnection {
|
||||
/* A server accepts connections */
|
||||
gboolean is_server;
|
||||
|
||||
/* The socket path itself */
|
||||
char *path;
|
||||
|
||||
/* File descriptor of the socket */
|
||||
int fd;
|
||||
/* Channel to watch */
|
||||
GIOChannel *chan;
|
||||
/* Event id returned by g_io_add_watch() */
|
||||
int conn_id;
|
||||
|
||||
/* Connections accepted by this connection */
|
||||
GSList *accepted_connections;
|
||||
|
||||
/* callback */
|
||||
void (*func) (const char *message, gpointer user_data);
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
test_is_socket (const char *path)
|
||||
{
|
||||
struct stat s;
|
||||
|
||||
if (stat (path, &s) == -1)
|
||||
return FALSE;
|
||||
|
||||
if (S_ISSOCK (s.st_mode))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_owned_by_user_and_socket (const char *path)
|
||||
{
|
||||
struct stat s;
|
||||
|
||||
if (stat (path, &s) == -1)
|
||||
return FALSE;
|
||||
|
||||
if (s.st_uid != geteuid ())
|
||||
return FALSE;
|
||||
|
||||
if ((s.st_mode & S_IFSOCK) != S_IFSOCK)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean server_cb (GIOChannel *source,
|
||||
GIOCondition condition, gpointer data);
|
||||
|
||||
static gboolean
|
||||
setup_connection (BaconMessageConnection *conn)
|
||||
{
|
||||
g_return_val_if_fail (conn->chan == NULL, FALSE);
|
||||
|
||||
conn->chan = g_io_channel_unix_new (conn->fd);
|
||||
if (!conn->chan) {
|
||||
return FALSE;
|
||||
}
|
||||
g_io_channel_set_line_term (conn->chan, "\n", 1);
|
||||
conn->conn_id = g_io_add_watch (conn->chan, G_IO_IN, server_cb, conn);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
accept_new_connection (BaconMessageConnection *server_conn)
|
||||
{
|
||||
BaconMessageConnection *conn;
|
||||
int alen;
|
||||
|
||||
g_return_if_fail (server_conn->is_server);
|
||||
|
||||
conn = g_new0 (BaconMessageConnection, 1);
|
||||
conn->is_server = FALSE;
|
||||
conn->func = server_conn->func;
|
||||
conn->data = server_conn->data;
|
||||
|
||||
conn->fd = accept (server_conn->fd, NULL, (guint *)&alen);
|
||||
|
||||
server_conn->accepted_connections =
|
||||
g_slist_prepend (server_conn->accepted_connections, conn);
|
||||
|
||||
setup_connection (conn);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
|
||||
{
|
||||
BaconMessageConnection *conn = (BaconMessageConnection *)data;
|
||||
char *message, *subs, buf;
|
||||
int cd, rc, offset;
|
||||
gboolean finished;
|
||||
|
||||
offset = 0;
|
||||
if (conn->is_server && conn->fd == g_io_channel_unix_get_fd (source)) {
|
||||
accept_new_connection (conn);
|
||||
return TRUE;
|
||||
}
|
||||
message = g_malloc (1);
|
||||
cd = conn->fd;
|
||||
rc = read (cd, &buf, 1);
|
||||
while (rc > 0 && buf != '\n')
|
||||
{
|
||||
message = g_realloc (message, rc + offset + 1);
|
||||
message[offset] = buf;
|
||||
offset = offset + rc;
|
||||
rc = read (cd, &buf, 1);
|
||||
}
|
||||
if (rc <= 0) {
|
||||
g_io_channel_shutdown (conn->chan, FALSE, NULL);
|
||||
g_io_channel_unref (conn->chan);
|
||||
conn->chan = NULL;
|
||||
close (conn->fd);
|
||||
conn->fd = -1;
|
||||
g_free (message);
|
||||
conn->conn_id = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
message[offset] = '\0';
|
||||
|
||||
subs = message;
|
||||
finished = FALSE;
|
||||
|
||||
while (finished == FALSE && *subs != '\0')
|
||||
{
|
||||
if (conn->func != NULL)
|
||||
(*conn->func) (subs, conn->data);
|
||||
|
||||
subs += strlen (subs) + 1;
|
||||
if (subs - message >= offset)
|
||||
finished = TRUE;
|
||||
}
|
||||
|
||||
g_free (message);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
find_file_with_pattern (const char *dir, const char *pattern)
|
||||
{
|
||||
GDir *filedir;
|
||||
char *found_filename;
|
||||
const char *filename;
|
||||
GPatternSpec *pat;
|
||||
|
||||
filedir = g_dir_open (dir, 0, NULL);
|
||||
if (filedir == NULL)
|
||||
return NULL;
|
||||
|
||||
pat = g_pattern_spec_new (pattern);
|
||||
if (pat == NULL)
|
||||
{
|
||||
g_dir_close (filedir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
found_filename = NULL;
|
||||
|
||||
while ((filename = g_dir_read_name (filedir)))
|
||||
{
|
||||
if (g_pattern_match_string (pat, filename))
|
||||
{
|
||||
char *tmp = g_build_filename (dir, filename, NULL);
|
||||
if (is_owned_by_user_and_socket (tmp))
|
||||
found_filename = g_strdup (filename);
|
||||
g_free (tmp);
|
||||
}
|
||||
|
||||
if (found_filename != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
g_pattern_spec_free (pat);
|
||||
g_dir_close (filedir);
|
||||
|
||||
return found_filename;
|
||||
}
|
||||
|
||||
static char *
|
||||
socket_filename (const char *prefix)
|
||||
{
|
||||
char *pattern, *newfile, *path, *filename;
|
||||
const char *tmpdir;
|
||||
|
||||
pattern = g_strdup_printf ("%s.%s.*", prefix, g_get_user_name ());
|
||||
tmpdir = g_get_tmp_dir ();
|
||||
filename = find_file_with_pattern (tmpdir, pattern);
|
||||
if (filename == NULL)
|
||||
{
|
||||
newfile = g_strdup_printf ("%s.%s.%u", prefix,
|
||||
g_get_user_name (), g_random_int ());
|
||||
path = g_build_filename (tmpdir, newfile, NULL);
|
||||
g_free (newfile);
|
||||
} else {
|
||||
path = g_build_filename (tmpdir, filename, NULL);
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
g_free (pattern);
|
||||
return path;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
try_server (BaconMessageConnection *conn)
|
||||
{
|
||||
struct sockaddr_un uaddr;
|
||||
|
||||
uaddr.sun_family = AF_UNIX;
|
||||
strncpy (uaddr.sun_path, conn->path,
|
||||
MIN (strlen(conn->path)+1, UNIX_PATH_MAX));
|
||||
conn->fd = socket (PF_UNIX, SOCK_STREAM, 0);
|
||||
if (bind (conn->fd, (struct sockaddr *) &uaddr, sizeof (uaddr)) == -1)
|
||||
{
|
||||
conn->fd = -1;
|
||||
return FALSE;
|
||||
}
|
||||
listen (conn->fd, 5);
|
||||
|
||||
if (!setup_connection (conn))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
try_client (BaconMessageConnection *conn)
|
||||
{
|
||||
struct sockaddr_un uaddr;
|
||||
|
||||
uaddr.sun_family = AF_UNIX;
|
||||
strncpy (uaddr.sun_path, conn->path,
|
||||
MIN(strlen(conn->path)+1, UNIX_PATH_MAX));
|
||||
conn->fd = socket (PF_UNIX, SOCK_STREAM, 0);
|
||||
if (connect (conn->fd, (struct sockaddr *) &uaddr,
|
||||
sizeof (uaddr)) == -1)
|
||||
{
|
||||
conn->fd = -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return setup_connection (conn);
|
||||
}
|
||||
|
||||
BaconMessageConnection *
|
||||
bacon_message_connection_new (const char *prefix)
|
||||
{
|
||||
BaconMessageConnection *conn;
|
||||
|
||||
g_return_val_if_fail (prefix != NULL, NULL);
|
||||
|
||||
conn = g_new0 (BaconMessageConnection, 1);
|
||||
conn->path = socket_filename (prefix);
|
||||
|
||||
if (test_is_socket (conn->path) == FALSE)
|
||||
{
|
||||
if (!try_server (conn))
|
||||
{
|
||||
bacon_message_connection_free (conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conn->is_server = TRUE;
|
||||
return conn;
|
||||
}
|
||||
|
||||
if (try_client (conn) == FALSE)
|
||||
{
|
||||
unlink (conn->path);
|
||||
try_server (conn);
|
||||
if (conn->fd == -1)
|
||||
{
|
||||
bacon_message_connection_free (conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conn->is_server = TRUE;
|
||||
return conn;
|
||||
}
|
||||
|
||||
conn->is_server = FALSE;
|
||||
return conn;
|
||||
}
|
||||
|
||||
void
|
||||
bacon_message_connection_free (BaconMessageConnection *conn)
|
||||
{
|
||||
GSList *child_conn;
|
||||
|
||||
g_return_if_fail (conn != NULL);
|
||||
/* Only servers can accept other connections */
|
||||
g_return_if_fail (conn->is_server != FALSE ||
|
||||
conn->accepted_connections == NULL);
|
||||
|
||||
child_conn = conn->accepted_connections;
|
||||
while (child_conn != NULL) {
|
||||
bacon_message_connection_free (child_conn->data);
|
||||
child_conn = g_slist_next (child_conn);
|
||||
}
|
||||
g_slist_free (conn->accepted_connections);
|
||||
|
||||
if (conn->conn_id) {
|
||||
g_source_remove (conn->conn_id);
|
||||
conn->conn_id = 0;
|
||||
}
|
||||
if (conn->chan) {
|
||||
g_io_channel_shutdown (conn->chan, FALSE, NULL);
|
||||
g_io_channel_unref (conn->chan);
|
||||
}
|
||||
|
||||
if (conn->is_server != FALSE) {
|
||||
unlink (conn->path);
|
||||
}
|
||||
if (conn->fd != -1) {
|
||||
close (conn->fd);
|
||||
}
|
||||
|
||||
g_free (conn->path);
|
||||
g_free (conn);
|
||||
}
|
||||
|
||||
void
|
||||
bacon_message_connection_set_callback (BaconMessageConnection *conn,
|
||||
BaconMessageReceivedFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_return_if_fail (conn != NULL);
|
||||
|
||||
conn->func = func;
|
||||
conn->data = user_data;
|
||||
}
|
||||
|
||||
void
|
||||
bacon_message_connection_send (BaconMessageConnection *conn,
|
||||
const char *message)
|
||||
{
|
||||
g_return_if_fail (conn != NULL);
|
||||
g_return_if_fail (message != NULL);
|
||||
|
||||
g_io_channel_write_chars (conn->chan, message, strlen (message),
|
||||
NULL, NULL);
|
||||
g_io_channel_write_chars (conn->chan, "\n", 1, NULL, NULL);
|
||||
g_io_channel_flush (conn->chan, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
bacon_message_connection_get_is_server (BaconMessageConnection *conn)
|
||||
{
|
||||
g_return_val_if_fail (conn != NULL, FALSE);
|
||||
|
||||
return conn->is_server;
|
||||
}
|
||||
|
||||
43
xed/bacon-message-connection.h
Normal file
43
xed/bacon-message-connection.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Bastien Nocera <hadess@hadess.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BACON_MESSAGE_CONNECTION_H
|
||||
#define BACON_MESSAGE_CONNECTION_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef void (*BaconMessageReceivedFunc) (const char *message,
|
||||
gpointer user_data);
|
||||
|
||||
typedef struct BaconMessageConnection BaconMessageConnection;
|
||||
|
||||
BaconMessageConnection *bacon_message_connection_new (const char *prefix);
|
||||
void bacon_message_connection_free (BaconMessageConnection *conn);
|
||||
void bacon_message_connection_set_callback (BaconMessageConnection *conn,
|
||||
BaconMessageReceivedFunc func,
|
||||
gpointer user_data);
|
||||
void bacon_message_connection_send (BaconMessageConnection *conn,
|
||||
const char *message);
|
||||
gboolean bacon_message_connection_get_is_server (BaconMessageConnection *conn);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* BACON_MESSAGE_CONNECTION_H */
|
||||
31
xed/dialogs/Makefile.am
Executable file
31
xed/dialogs/Makefile.am
Executable file
@@ -0,0 +1,31 @@
|
||||
uidir = $(datadir)/xed/ui/
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_builddir) \
|
||||
-I$(top_srcdir)/xed \
|
||||
-I$(top_builddir)/xed \
|
||||
$(XED_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(DISABLE_DEPRECATED_CFLAGS)
|
||||
|
||||
noinst_LTLIBRARIES = libdialogs.la
|
||||
|
||||
libdialogs_la_SOURCES = \
|
||||
xed-preferences-dialog.h \
|
||||
xed-preferences-dialog.c \
|
||||
xed-close-confirmation-dialog.c \
|
||||
xed-close-confirmation-dialog.h \
|
||||
xed-encodings-dialog.c \
|
||||
xed-encodings-dialog.h \
|
||||
xed-search-dialog.h \
|
||||
xed-search-dialog.c
|
||||
|
||||
ui_DATA = \
|
||||
xed-encodings-dialog.ui \
|
||||
xed-preferences-dialog.ui \
|
||||
xed-search-dialog.ui
|
||||
|
||||
EXTRA_DIST = $(ui_DATA)
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
797
xed/dialogs/xed-close-confirmation-dialog.c
Executable file
797
xed/dialogs/xed-close-confirmation-dialog.c
Executable file
@@ -0,0 +1,797 @@
|
||||
/*
|
||||
* xed-close-confirmation-dialog.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2004-2005 GNOME Foundation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2004-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "xed-close-confirmation-dialog.h"
|
||||
#include <xed/xed-app.h>
|
||||
#include <xed/xed-utils.h>
|
||||
#include <xed/xed-window.h>
|
||||
|
||||
|
||||
/* Properties */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_UNSAVED_DOCUMENTS,
|
||||
PROP_LOGOUT_MODE
|
||||
};
|
||||
|
||||
/* Mode */
|
||||
enum
|
||||
{
|
||||
SINGLE_DOC_MODE,
|
||||
MULTIPLE_DOCS_MODE
|
||||
};
|
||||
|
||||
/* Columns */
|
||||
enum
|
||||
{
|
||||
SAVE_COLUMN,
|
||||
NAME_COLUMN,
|
||||
DOC_COLUMN, /* a handy pointer to the document */
|
||||
N_COLUMNS
|
||||
};
|
||||
|
||||
struct _XedCloseConfirmationDialogPrivate
|
||||
{
|
||||
gboolean logout_mode;
|
||||
|
||||
GList *unsaved_documents;
|
||||
|
||||
GList *selected_documents;
|
||||
|
||||
GtkTreeModel *list_store;
|
||||
|
||||
};
|
||||
|
||||
#define XED_CLOSE_CONFIRMATION_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
|
||||
XED_TYPE_CLOSE_CONFIRMATION_DIALOG, \
|
||||
XedCloseConfirmationDialogPrivate))
|
||||
|
||||
#define GET_MODE(priv) (((priv->unsaved_documents != NULL) && \
|
||||
(priv->unsaved_documents->next == NULL)) ? \
|
||||
SINGLE_DOC_MODE : MULTIPLE_DOCS_MODE)
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
#define gtk_hbox_new(X,Y) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,Y)
|
||||
#define gtk_vbox_new(X,Y) gtk_box_new(GTK_ORIENTATION_VERTICAL,Y)
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE(XedCloseConfirmationDialog, xed_close_confirmation_dialog, GTK_TYPE_DIALOG)
|
||||
|
||||
static void set_unsaved_document (XedCloseConfirmationDialog *dlg,
|
||||
const GList *list);
|
||||
|
||||
static GList *get_selected_docs (GtkTreeModel *store);
|
||||
|
||||
/* Since we connect in the costructor we are sure this handler will be called
|
||||
* before the user ones
|
||||
*/
|
||||
static void
|
||||
response_cb (XedCloseConfirmationDialog *dlg,
|
||||
gint response_id,
|
||||
gpointer data)
|
||||
{
|
||||
XedCloseConfirmationDialogPrivate *priv;
|
||||
|
||||
g_return_if_fail (XED_IS_CLOSE_CONFIRMATION_DIALOG (dlg));
|
||||
|
||||
priv = dlg->priv;
|
||||
|
||||
if (priv->selected_documents != NULL)
|
||||
g_list_free (priv->selected_documents);
|
||||
|
||||
if (response_id == GTK_RESPONSE_YES)
|
||||
{
|
||||
if (GET_MODE (priv) == SINGLE_DOC_MODE)
|
||||
{
|
||||
priv->selected_documents =
|
||||
g_list_copy (priv->unsaved_documents);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_return_if_fail (priv->list_store);
|
||||
|
||||
priv->selected_documents =
|
||||
get_selected_docs (priv->list_store);
|
||||
}
|
||||
}
|
||||
else
|
||||
priv->selected_documents = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
set_logout_mode (XedCloseConfirmationDialog *dlg,
|
||||
gboolean logout_mode)
|
||||
{
|
||||
dlg->priv->logout_mode = logout_mode;
|
||||
|
||||
if (logout_mode)
|
||||
{
|
||||
gtk_dialog_add_button (GTK_DIALOG (dlg),
|
||||
_("Log Out _without Saving"),
|
||||
GTK_RESPONSE_NO);
|
||||
|
||||
xed_dialog_add_button (GTK_DIALOG (dlg),
|
||||
_("_Cancel Logout"),
|
||||
GTK_STOCK_CANCEL,
|
||||
GTK_RESPONSE_CANCEL);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_dialog_add_button (GTK_DIALOG (dlg),
|
||||
_("Close _without Saving"),
|
||||
GTK_RESPONSE_NO);
|
||||
|
||||
gtk_dialog_add_button (GTK_DIALOG (dlg),
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
|
||||
}
|
||||
|
||||
|
||||
const gchar *stock_id = GTK_STOCK_SAVE;
|
||||
|
||||
if (GET_MODE (dlg->priv) == SINGLE_DOC_MODE)
|
||||
{
|
||||
XedDocument *doc;
|
||||
|
||||
doc = XED_DOCUMENT (dlg->priv->unsaved_documents->data);
|
||||
|
||||
if (xed_document_get_readonly (doc) ||
|
||||
xed_document_is_untitled (doc))
|
||||
stock_id = GTK_STOCK_SAVE_AS;
|
||||
}
|
||||
|
||||
gtk_dialog_add_button (GTK_DIALOG (dlg),
|
||||
stock_id,
|
||||
GTK_RESPONSE_YES);
|
||||
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dlg),
|
||||
GTK_RESPONSE_YES);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_close_confirmation_dialog_init (XedCloseConfirmationDialog *dlg)
|
||||
{
|
||||
AtkObject *atk_obj;
|
||||
|
||||
dlg->priv = XED_CLOSE_CONFIRMATION_DIALOG_GET_PRIVATE (dlg);
|
||||
|
||||
gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
|
||||
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
|
||||
14);
|
||||
gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
|
||||
gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dlg), TRUE);
|
||||
|
||||
gtk_window_set_title (GTK_WINDOW (dlg), "");
|
||||
|
||||
gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
|
||||
gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
|
||||
|
||||
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (dlg));
|
||||
atk_object_set_role (atk_obj, ATK_ROLE_ALERT);
|
||||
atk_object_set_name (atk_obj, _("Question"));
|
||||
|
||||
g_signal_connect (dlg,
|
||||
"response",
|
||||
G_CALLBACK (response_cb),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_close_confirmation_dialog_finalize (GObject *object)
|
||||
{
|
||||
XedCloseConfirmationDialogPrivate *priv;
|
||||
|
||||
priv = XED_CLOSE_CONFIRMATION_DIALOG (object)->priv;
|
||||
|
||||
if (priv->unsaved_documents != NULL)
|
||||
g_list_free (priv->unsaved_documents);
|
||||
|
||||
if (priv->selected_documents != NULL)
|
||||
g_list_free (priv->selected_documents);
|
||||
|
||||
/* Call the parent's destructor */
|
||||
G_OBJECT_CLASS (xed_close_confirmation_dialog_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_close_confirmation_dialog_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedCloseConfirmationDialog *dlg;
|
||||
|
||||
dlg = XED_CLOSE_CONFIRMATION_DIALOG (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_UNSAVED_DOCUMENTS:
|
||||
set_unsaved_document (dlg, g_value_get_pointer (value));
|
||||
break;
|
||||
|
||||
case PROP_LOGOUT_MODE:
|
||||
set_logout_mode (dlg, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_close_confirmation_dialog_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedCloseConfirmationDialogPrivate *priv;
|
||||
|
||||
priv = XED_CLOSE_CONFIRMATION_DIALOG (object)->priv;
|
||||
|
||||
switch( prop_id )
|
||||
{
|
||||
case PROP_UNSAVED_DOCUMENTS:
|
||||
g_value_set_pointer (value, priv->unsaved_documents);
|
||||
break;
|
||||
|
||||
case PROP_LOGOUT_MODE:
|
||||
g_value_set_boolean (value, priv->logout_mode);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_close_confirmation_dialog_class_init (XedCloseConfirmationDialogClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = xed_close_confirmation_dialog_set_property;
|
||||
gobject_class->get_property = xed_close_confirmation_dialog_get_property;
|
||||
gobject_class->finalize = xed_close_confirmation_dialog_finalize;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (XedCloseConfirmationDialogPrivate));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_UNSAVED_DOCUMENTS,
|
||||
g_param_spec_pointer ("unsaved_documents",
|
||||
"Unsaved Documents",
|
||||
"List of Unsaved Documents",
|
||||
(G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY)));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_LOGOUT_MODE,
|
||||
g_param_spec_boolean ("logout_mode",
|
||||
"Logout Mode",
|
||||
"Whether the dialog is in logout mode",
|
||||
FALSE,
|
||||
(G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY)));
|
||||
}
|
||||
|
||||
static GList *
|
||||
get_selected_docs (GtkTreeModel *store)
|
||||
{
|
||||
GList *list;
|
||||
gboolean valid;
|
||||
GtkTreeIter iter;
|
||||
|
||||
list = NULL;
|
||||
valid = gtk_tree_model_get_iter_first (store, &iter);
|
||||
|
||||
while (valid)
|
||||
{
|
||||
gboolean to_save;
|
||||
XedDocument *doc;
|
||||
|
||||
gtk_tree_model_get (store, &iter,
|
||||
SAVE_COLUMN, &to_save,
|
||||
DOC_COLUMN, &doc,
|
||||
-1);
|
||||
if (to_save)
|
||||
list = g_list_prepend (list, doc);
|
||||
|
||||
valid = gtk_tree_model_iter_next (store, &iter);
|
||||
}
|
||||
|
||||
list = g_list_reverse (list);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
GList *
|
||||
xed_close_confirmation_dialog_get_selected_documents (XedCloseConfirmationDialog *dlg)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_CLOSE_CONFIRMATION_DIALOG (dlg), NULL);
|
||||
|
||||
return g_list_copy (dlg->priv->selected_documents);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
xed_close_confirmation_dialog_new (GtkWindow *parent,
|
||||
GList *unsaved_documents,
|
||||
gboolean logout_mode)
|
||||
{
|
||||
GtkWidget *dlg;
|
||||
g_return_val_if_fail (unsaved_documents != NULL, NULL);
|
||||
|
||||
dlg = GTK_WIDGET (g_object_new (XED_TYPE_CLOSE_CONFIRMATION_DIALOG,
|
||||
"unsaved_documents", unsaved_documents,
|
||||
"logout_mode", logout_mode,
|
||||
NULL));
|
||||
g_return_val_if_fail (dlg != NULL, NULL);
|
||||
|
||||
if (parent != NULL)
|
||||
{
|
||||
gtk_window_group_add_window (xed_window_get_group (XED_WINDOW (parent)),
|
||||
GTK_WINDOW (dlg));
|
||||
|
||||
gtk_window_set_transient_for (GTK_WINDOW (dlg), parent);
|
||||
}
|
||||
|
||||
return dlg;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
xed_close_confirmation_dialog_new_single (GtkWindow *parent,
|
||||
XedDocument *doc,
|
||||
gboolean logout_mode)
|
||||
{
|
||||
GtkWidget *dlg;
|
||||
GList *unsaved_documents;
|
||||
g_return_val_if_fail (doc != NULL, NULL);
|
||||
|
||||
unsaved_documents = g_list_prepend (NULL, doc);
|
||||
|
||||
dlg = xed_close_confirmation_dialog_new (parent,
|
||||
unsaved_documents,
|
||||
logout_mode);
|
||||
|
||||
g_list_free (unsaved_documents);
|
||||
|
||||
return dlg;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
get_text_secondary_label (XedDocument *doc)
|
||||
{
|
||||
glong seconds;
|
||||
gchar *secondary_msg;
|
||||
|
||||
seconds = MAX (1, _xed_document_get_seconds_since_last_save_or_load (doc));
|
||||
|
||||
if (seconds < 55)
|
||||
{
|
||||
secondary_msg = g_strdup_printf (
|
||||
ngettext ("If you don't save, changes from the last %ld second "
|
||||
"will be permanently lost.",
|
||||
"If you don't save, changes from the last %ld seconds "
|
||||
"will be permanently lost.",
|
||||
seconds),
|
||||
seconds);
|
||||
}
|
||||
else if (seconds < 75) /* 55 <= seconds < 75 */
|
||||
{
|
||||
secondary_msg = g_strdup (_("If you don't save, changes from the last minute "
|
||||
"will be permanently lost."));
|
||||
}
|
||||
else if (seconds < 110) /* 75 <= seconds < 110 */
|
||||
{
|
||||
secondary_msg = g_strdup_printf (
|
||||
ngettext ("If you don't save, changes from the last minute and %ld "
|
||||
"second will be permanently lost.",
|
||||
"If you don't save, changes from the last minute and %ld "
|
||||
"seconds will be permanently lost.",
|
||||
seconds - 60 ),
|
||||
seconds - 60);
|
||||
}
|
||||
else if (seconds < 3600)
|
||||
{
|
||||
secondary_msg = g_strdup_printf (
|
||||
ngettext ("If you don't save, changes from the last %ld minute "
|
||||
"will be permanently lost.",
|
||||
"If you don't save, changes from the last %ld minutes "
|
||||
"will be permanently lost.",
|
||||
seconds / 60),
|
||||
seconds / 60);
|
||||
}
|
||||
else if (seconds < 7200)
|
||||
{
|
||||
gint minutes;
|
||||
seconds -= 3600;
|
||||
|
||||
minutes = seconds / 60;
|
||||
if (minutes < 5)
|
||||
{
|
||||
secondary_msg = g_strdup (_("If you don't save, changes from the last hour "
|
||||
"will be permanently lost."));
|
||||
}
|
||||
else
|
||||
{
|
||||
secondary_msg = g_strdup_printf (
|
||||
ngettext ("If you don't save, changes from the last hour and %d "
|
||||
"minute will be permanently lost.",
|
||||
"If you don't save, changes from the last hour and %d "
|
||||
"minutes will be permanently lost.",
|
||||
minutes),
|
||||
minutes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint hours;
|
||||
|
||||
hours = seconds / 3600;
|
||||
|
||||
secondary_msg = g_strdup_printf (
|
||||
ngettext ("If you don't save, changes from the last %d hour "
|
||||
"will be permanently lost.",
|
||||
"If you don't save, changes from the last %d hours "
|
||||
"will be permanently lost.",
|
||||
hours),
|
||||
hours);
|
||||
}
|
||||
|
||||
return secondary_msg;
|
||||
}
|
||||
|
||||
static void
|
||||
build_single_doc_dialog (XedCloseConfirmationDialog *dlg)
|
||||
{
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *primary_label;
|
||||
GtkWidget *secondary_label;
|
||||
GtkWidget *image;
|
||||
XedDocument *doc;
|
||||
gchar *doc_name;
|
||||
gchar *str;
|
||||
gchar *markup_str;
|
||||
|
||||
g_return_if_fail (dlg->priv->unsaved_documents->data != NULL);
|
||||
doc = XED_DOCUMENT (dlg->priv->unsaved_documents->data);
|
||||
|
||||
/* Image */
|
||||
#if GTK_CHECK_VERSION (3, 10, 0)
|
||||
image = gtk_image_new_from_icon_name ("dialog-warning",
|
||||
GTK_ICON_SIZE_DIALOG);
|
||||
#else
|
||||
image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
|
||||
GTK_ICON_SIZE_DIALOG);
|
||||
#endif
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
gtk_widget_set_halign (image, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (image, GTK_ALIGN_END);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
|
||||
#endif
|
||||
|
||||
/* Primary label */
|
||||
primary_label = gtk_label_new (NULL);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
|
||||
gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
|
||||
#if GTK_CHECK_VERSION (3, 16, 0)
|
||||
gtk_label_set_xalign (GTK_LABEL (primary_label), 0.0);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (primary_label), 0.0, 0.5);
|
||||
#endif
|
||||
gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
|
||||
gtk_widget_set_can_focus (GTK_WIDGET (primary_label), FALSE);
|
||||
|
||||
doc_name = xed_document_get_short_name_for_display (doc);
|
||||
|
||||
str = g_markup_printf_escaped (_("Save changes to document \"%s\" before closing?"), doc_name);
|
||||
|
||||
g_free (doc_name);
|
||||
|
||||
markup_str = g_strconcat ("<span weight=\"bold\" size=\"larger\">", str, "</span>", NULL);
|
||||
g_free (str);
|
||||
|
||||
gtk_label_set_markup (GTK_LABEL (primary_label), markup_str);
|
||||
g_free (markup_str);
|
||||
|
||||
/* Secondary label */
|
||||
str = get_text_secondary_label (doc);
|
||||
secondary_label = gtk_label_new (str);
|
||||
g_free (str);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
|
||||
#if GTK_CHECK_VERSION (3, 16, 0)
|
||||
gtk_label_set_xalign (GTK_LABEL (secondary_label), 0.0);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (secondary_label), 0.0, 0.5);
|
||||
#endif
|
||||
gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
|
||||
gtk_widget_set_can_focus (GTK_WIDGET (secondary_label), FALSE);
|
||||
|
||||
hbox = gtk_hbox_new (FALSE, 12);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
|
||||
|
||||
vbox = gtk_vbox_new (FALSE, 12);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (vbox), primary_label, FALSE, FALSE, 0);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (vbox), secondary_label, FALSE, FALSE, 0);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
|
||||
hbox,
|
||||
FALSE,
|
||||
FALSE,
|
||||
0);
|
||||
|
||||
gtk_widget_show_all (hbox);
|
||||
}
|
||||
|
||||
static void
|
||||
populate_model (GtkTreeModel *store, GList *docs)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
|
||||
while (docs != NULL)
|
||||
{
|
||||
XedDocument *doc;
|
||||
gchar *name;
|
||||
|
||||
doc = XED_DOCUMENT (docs->data);
|
||||
|
||||
name = xed_document_get_short_name_for_display (doc);
|
||||
|
||||
gtk_list_store_append (GTK_LIST_STORE (store), &iter);
|
||||
gtk_list_store_set (GTK_LIST_STORE (store), &iter,
|
||||
SAVE_COLUMN, TRUE,
|
||||
NAME_COLUMN, name,
|
||||
DOC_COLUMN, doc,
|
||||
-1);
|
||||
|
||||
g_free (name);
|
||||
|
||||
docs = g_list_next (docs);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
save_toggled (GtkCellRendererToggle *renderer, gchar *path_str, GtkTreeModel *store)
|
||||
{
|
||||
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
|
||||
GtkTreeIter iter;
|
||||
gboolean active;
|
||||
|
||||
gtk_tree_model_get_iter (store, &iter, path);
|
||||
gtk_tree_model_get (store, &iter, SAVE_COLUMN, &active, -1);
|
||||
|
||||
active ^= 1;
|
||||
|
||||
gtk_list_store_set (GTK_LIST_STORE (store), &iter,
|
||||
SAVE_COLUMN, active, -1);
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_treeview (XedCloseConfirmationDialogPrivate *priv)
|
||||
{
|
||||
GtkListStore *store;
|
||||
GtkWidget *treeview;
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
|
||||
treeview = gtk_tree_view_new ();
|
||||
gtk_widget_set_size_request (treeview, 260, 120);
|
||||
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
|
||||
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), FALSE);
|
||||
|
||||
/* Create and populate the model */
|
||||
store = gtk_list_store_new (N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER);
|
||||
populate_model (GTK_TREE_MODEL (store), priv->unsaved_documents);
|
||||
|
||||
/* Set model to the treeview */
|
||||
gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
|
||||
g_object_unref (store);
|
||||
|
||||
priv->list_store = GTK_TREE_MODEL (store);
|
||||
|
||||
/* Add columns */
|
||||
|
||||
renderer = gtk_cell_renderer_toggle_new ();
|
||||
g_signal_connect (renderer, "toggled",
|
||||
G_CALLBACK (save_toggled), store);
|
||||
|
||||
column = gtk_tree_view_column_new_with_attributes ("Save?",
|
||||
renderer,
|
||||
"active",
|
||||
SAVE_COLUMN,
|
||||
NULL);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
column = gtk_tree_view_column_new_with_attributes ("Name",
|
||||
renderer,
|
||||
"text",
|
||||
NAME_COLUMN,
|
||||
NULL);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
|
||||
|
||||
return treeview;
|
||||
}
|
||||
|
||||
static void
|
||||
build_multiple_docs_dialog (XedCloseConfirmationDialog *dlg)
|
||||
{
|
||||
XedCloseConfirmationDialogPrivate *priv;
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *image;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *primary_label;
|
||||
GtkWidget *vbox2;
|
||||
GtkWidget *select_label;
|
||||
GtkWidget *scrolledwindow;
|
||||
GtkWidget *treeview;
|
||||
GtkWidget *secondary_label;
|
||||
gchar *str;
|
||||
gchar *markup_str;
|
||||
|
||||
priv = dlg->priv;
|
||||
|
||||
hbox = gtk_hbox_new (FALSE, 12);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
|
||||
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
|
||||
hbox, TRUE, TRUE, 0);
|
||||
|
||||
/* Image */
|
||||
#if GTK_CHECK_VERSION (3, 10, 0)
|
||||
image = gtk_image_new_from_icon_name ("dialog-warning",
|
||||
GTK_ICON_SIZE_DIALOG);
|
||||
#else
|
||||
image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
|
||||
GTK_ICON_SIZE_DIALOG);
|
||||
#endif
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (image, GTK_ALIGN_START);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
|
||||
#endif
|
||||
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
|
||||
|
||||
vbox = gtk_vbox_new (FALSE, 12);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
|
||||
|
||||
/* Primary label */
|
||||
primary_label = gtk_label_new (NULL);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
|
||||
gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
|
||||
#if GTK_CHECK_VERSION (3, 16, 0)
|
||||
gtk_label_set_xalign (GTK_LABEL (primary_label), 0.0);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (primary_label), 0.0, 0.5);
|
||||
#endif
|
||||
gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
|
||||
|
||||
str = g_strdup_printf (
|
||||
ngettext ("There is %d document with unsaved changes. "
|
||||
"Save changes before closing?",
|
||||
"There are %d documents with unsaved changes. "
|
||||
"Save changes before closing?",
|
||||
g_list_length (priv->unsaved_documents)),
|
||||
g_list_length (priv->unsaved_documents));
|
||||
|
||||
markup_str = g_strconcat ("<span weight=\"bold\" size=\"larger\">", str, "</span>", NULL);
|
||||
g_free (str);
|
||||
|
||||
gtk_label_set_markup (GTK_LABEL (primary_label), markup_str);
|
||||
g_free (markup_str);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), primary_label, FALSE, FALSE, 0);
|
||||
|
||||
vbox2 = gtk_vbox_new (FALSE, 8);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
|
||||
|
||||
select_label = gtk_label_new_with_mnemonic (_("S_elect the documents you want to save:"));
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (vbox2), select_label, FALSE, FALSE, 0);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (select_label), TRUE);
|
||||
#if GTK_CHECK_VERSION (3, 16, 0)
|
||||
gtk_label_set_xalign (GTK_LABEL (select_label), 0.0);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (select_label), 0.0, 0.5);
|
||||
#endif
|
||||
|
||||
scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_box_pack_start (GTK_BOX (vbox2), scrolledwindow, TRUE, TRUE, 0);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow),
|
||||
GTK_SHADOW_IN);
|
||||
|
||||
treeview = create_treeview (priv);
|
||||
gtk_container_add (GTK_CONTAINER (scrolledwindow), treeview);
|
||||
|
||||
/* Secondary label */
|
||||
secondary_label = gtk_label_new (_("If you don't save, "
|
||||
"all your changes will be permanently lost."));
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (vbox2), secondary_label, FALSE, FALSE, 0);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
|
||||
#if GTK_CHECK_VERSION (3, 16, 0)
|
||||
gtk_label_set_xalign (GTK_LABEL (secondary_label), 0.0);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (secondary_label), 0.0, 0.5);
|
||||
#endif
|
||||
gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
|
||||
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (select_label), treeview);
|
||||
|
||||
gtk_widget_show_all (hbox);
|
||||
}
|
||||
|
||||
static void
|
||||
set_unsaved_document (XedCloseConfirmationDialog *dlg,
|
||||
const GList *list)
|
||||
{
|
||||
XedCloseConfirmationDialogPrivate *priv;
|
||||
|
||||
g_return_if_fail (list != NULL);
|
||||
|
||||
priv = dlg->priv;
|
||||
g_return_if_fail (priv->unsaved_documents == NULL);
|
||||
|
||||
priv->unsaved_documents = g_list_copy ((GList *)list);
|
||||
|
||||
if (GET_MODE (priv) == SINGLE_DOC_MODE)
|
||||
{
|
||||
build_single_doc_dialog (dlg);
|
||||
}
|
||||
else
|
||||
{
|
||||
build_multiple_docs_dialog (dlg);
|
||||
}
|
||||
}
|
||||
|
||||
const GList *
|
||||
xed_close_confirmation_dialog_get_unsaved_documents (XedCloseConfirmationDialog *dlg)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_CLOSE_CONFIRMATION_DIALOG (dlg), NULL);
|
||||
|
||||
return dlg->priv->unsaved_documents;
|
||||
}
|
||||
75
xed/dialogs/xed-close-confirmation-dialog.h
Executable file
75
xed/dialogs/xed-close-confirmation-dialog.h
Executable file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* xed-close-confirmation-dialog.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2004-2005 GNOME Foundation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2004-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*/
|
||||
|
||||
#ifndef __XED_CLOSE_CONFIRMATION_DIALOG_H__
|
||||
#define __XED_CLOSE_CONFIRMATION_DIALOG_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <xed/xed-document.h>
|
||||
|
||||
#define XED_TYPE_CLOSE_CONFIRMATION_DIALOG (xed_close_confirmation_dialog_get_type ())
|
||||
#define XED_CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_CLOSE_CONFIRMATION_DIALOG, XedCloseConfirmationDialog))
|
||||
#define XED_CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_CLOSE_CONFIRMATION_DIALOG, XedCloseConfirmationDialogClass))
|
||||
#define XED_IS_CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_CLOSE_CONFIRMATION_DIALOG))
|
||||
#define XED_IS_CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_CLOSE_CONFIRMATION_DIALOG))
|
||||
#define XED_CLOSE_CONFIRMATION_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),XED_TYPE_CLOSE_CONFIRMATION_DIALOG, XedCloseConfirmationDialogClass))
|
||||
|
||||
typedef struct _XedCloseConfirmationDialog XedCloseConfirmationDialog;
|
||||
typedef struct _XedCloseConfirmationDialogClass XedCloseConfirmationDialogClass;
|
||||
typedef struct _XedCloseConfirmationDialogPrivate XedCloseConfirmationDialogPrivate;
|
||||
|
||||
struct _XedCloseConfirmationDialog
|
||||
{
|
||||
GtkDialog parent;
|
||||
|
||||
/*< private > */
|
||||
XedCloseConfirmationDialogPrivate *priv;
|
||||
};
|
||||
|
||||
struct _XedCloseConfirmationDialogClass
|
||||
{
|
||||
GtkDialogClass parent_class;
|
||||
};
|
||||
|
||||
GType xed_close_confirmation_dialog_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget *xed_close_confirmation_dialog_new (GtkWindow *parent,
|
||||
GList *unsaved_documents,
|
||||
gboolean logout_mode);
|
||||
GtkWidget *xed_close_confirmation_dialog_new_single (GtkWindow *parent,
|
||||
XedDocument *doc,
|
||||
gboolean logout_mode);
|
||||
|
||||
const GList *xed_close_confirmation_dialog_get_unsaved_documents (XedCloseConfirmationDialog *dlg);
|
||||
|
||||
GList *xed_close_confirmation_dialog_get_selected_documents (XedCloseConfirmationDialog *dlg);
|
||||
|
||||
#endif /* __XED_CLOSE_CONFIRMATION_DIALOG_H__ */
|
||||
|
||||
498
xed/dialogs/xed-encodings-dialog.c
Executable file
498
xed/dialogs/xed-encodings-dialog.c
Executable file
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* xed-encodings-dialog.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "xed-encodings-dialog.h"
|
||||
#include "xed-encodings.h"
|
||||
#include "xed-prefs-manager.h"
|
||||
#include "xed-utils.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-help.h"
|
||||
#include "xed-dirs.h"
|
||||
|
||||
#define XED_ENCODINGS_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
|
||||
XED_TYPE_ENCODINGS_DIALOG, \
|
||||
XedEncodingsDialogPrivate))
|
||||
|
||||
struct _XedEncodingsDialogPrivate
|
||||
{
|
||||
GtkListStore *available_liststore;
|
||||
GtkListStore *displayed_liststore;
|
||||
GtkWidget *available_treeview;
|
||||
GtkWidget *displayed_treeview;
|
||||
GtkWidget *add_button;
|
||||
GtkWidget *remove_button;
|
||||
|
||||
GSList *show_in_menu_list;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(XedEncodingsDialog, xed_encodings_dialog, GTK_TYPE_DIALOG)
|
||||
|
||||
static void
|
||||
xed_encodings_dialog_finalize (GObject *object)
|
||||
{
|
||||
XedEncodingsDialogPrivate *priv = XED_ENCODINGS_DIALOG (object)->priv;
|
||||
|
||||
g_slist_free (priv->show_in_menu_list);
|
||||
|
||||
G_OBJECT_CLASS (xed_encodings_dialog_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_encodings_dialog_class_init (XedEncodingsDialogClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = xed_encodings_dialog_finalize;
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (XedEncodingsDialogPrivate));
|
||||
}
|
||||
|
||||
enum {
|
||||
COLUMN_NAME,
|
||||
COLUMN_CHARSET,
|
||||
N_COLUMNS
|
||||
};
|
||||
|
||||
static void
|
||||
count_selected_items_func (GtkTreeModel *model,
|
||||
GtkTreePath *path,
|
||||
GtkTreeIter *iter,
|
||||
gpointer data)
|
||||
{
|
||||
int *count = data;
|
||||
|
||||
*count += 1;
|
||||
}
|
||||
|
||||
static void
|
||||
available_selection_changed_callback (GtkTreeSelection *selection,
|
||||
XedEncodingsDialog *dialogs)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
gtk_tree_selection_selected_foreach (selection,
|
||||
count_selected_items_func,
|
||||
&count);
|
||||
|
||||
gtk_widget_set_sensitive (dialogs->priv->add_button, count > 0);
|
||||
}
|
||||
|
||||
static void
|
||||
displayed_selection_changed_callback (GtkTreeSelection *selection,
|
||||
XedEncodingsDialog *dialogs)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
gtk_tree_selection_selected_foreach (selection,
|
||||
count_selected_items_func,
|
||||
&count);
|
||||
|
||||
gtk_widget_set_sensitive (dialogs->priv->remove_button, count > 0);
|
||||
}
|
||||
|
||||
static void
|
||||
get_selected_encodings_func (GtkTreeModel *model,
|
||||
GtkTreePath *path,
|
||||
GtkTreeIter *iter,
|
||||
gpointer data)
|
||||
{
|
||||
GSList **list = data;
|
||||
gchar *charset;
|
||||
const XedEncoding *enc;
|
||||
|
||||
charset = NULL;
|
||||
gtk_tree_model_get (model, iter, COLUMN_CHARSET, &charset, -1);
|
||||
|
||||
enc = xed_encoding_get_from_charset (charset);
|
||||
g_free (charset);
|
||||
|
||||
*list = g_slist_prepend (*list, (gpointer)enc);
|
||||
}
|
||||
|
||||
static void
|
||||
update_shown_in_menu_tree_model (GtkListStore *store,
|
||||
GSList *list)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
|
||||
gtk_list_store_clear (store);
|
||||
|
||||
while (list != NULL)
|
||||
{
|
||||
const XedEncoding *enc;
|
||||
|
||||
enc = (const XedEncoding*) list->data;
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter,
|
||||
COLUMN_CHARSET,
|
||||
xed_encoding_get_charset (enc),
|
||||
COLUMN_NAME,
|
||||
xed_encoding_get_name (enc), -1);
|
||||
|
||||
list = g_slist_next (list);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_button_clicked_callback (GtkWidget *button,
|
||||
XedEncodingsDialog *dialog)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
GSList *encodings;
|
||||
GSList *tmp;
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->available_treeview));
|
||||
|
||||
encodings = NULL;
|
||||
gtk_tree_selection_selected_foreach (selection,
|
||||
get_selected_encodings_func,
|
||||
&encodings);
|
||||
|
||||
tmp = encodings;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
if (g_slist_find (dialog->priv->show_in_menu_list, tmp->data) == NULL)
|
||||
dialog->priv->show_in_menu_list = g_slist_prepend (dialog->priv->show_in_menu_list,
|
||||
tmp->data);
|
||||
|
||||
tmp = g_slist_next (tmp);
|
||||
}
|
||||
|
||||
g_slist_free (encodings);
|
||||
|
||||
update_shown_in_menu_tree_model (GTK_LIST_STORE (dialog->priv->displayed_liststore),
|
||||
dialog->priv->show_in_menu_list);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_button_clicked_callback (GtkWidget *button,
|
||||
XedEncodingsDialog *dialog)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
GSList *encodings;
|
||||
GSList *tmp;
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->displayed_treeview));
|
||||
|
||||
encodings = NULL;
|
||||
gtk_tree_selection_selected_foreach (selection,
|
||||
get_selected_encodings_func,
|
||||
&encodings);
|
||||
|
||||
tmp = encodings;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
dialog->priv->show_in_menu_list = g_slist_remove (dialog->priv->show_in_menu_list,
|
||||
tmp->data);
|
||||
|
||||
tmp = g_slist_next (tmp);
|
||||
}
|
||||
|
||||
g_slist_free (encodings);
|
||||
|
||||
update_shown_in_menu_tree_model (GTK_LIST_STORE (dialog->priv->displayed_liststore),
|
||||
dialog->priv->show_in_menu_list);
|
||||
}
|
||||
|
||||
static void
|
||||
init_shown_in_menu_tree_model (XedEncodingsDialog *dialog)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GSList *list, *tmp;
|
||||
|
||||
/* add data to the list store */
|
||||
list = xed_prefs_manager_get_shown_in_menu_encodings ();
|
||||
|
||||
tmp = list;
|
||||
|
||||
while (tmp != NULL)
|
||||
{
|
||||
const XedEncoding *enc;
|
||||
|
||||
enc = (const XedEncoding *) tmp->data;
|
||||
|
||||
dialog->priv->show_in_menu_list = g_slist_prepend (dialog->priv->show_in_menu_list,
|
||||
tmp->data);
|
||||
|
||||
gtk_list_store_append (dialog->priv->displayed_liststore,
|
||||
&iter);
|
||||
gtk_list_store_set (dialog->priv->displayed_liststore,
|
||||
&iter,
|
||||
COLUMN_CHARSET,
|
||||
xed_encoding_get_charset (enc),
|
||||
COLUMN_NAME,
|
||||
xed_encoding_get_name (enc), -1);
|
||||
|
||||
tmp = g_slist_next (tmp);
|
||||
}
|
||||
|
||||
g_slist_free (list);
|
||||
}
|
||||
|
||||
static void
|
||||
response_handler (GtkDialog *dialog,
|
||||
gint response_id,
|
||||
XedEncodingsDialog *dlg)
|
||||
{
|
||||
if (response_id == GTK_RESPONSE_HELP)
|
||||
{
|
||||
xed_help_display (GTK_WINDOW (dialog), "xed", NULL);
|
||||
g_signal_stop_emission_by_name (dialog, "response");
|
||||
return;
|
||||
}
|
||||
|
||||
if (response_id == GTK_RESPONSE_OK)
|
||||
{
|
||||
g_return_if_fail (xed_prefs_manager_shown_in_menu_encodings_can_set ());
|
||||
xed_prefs_manager_set_shown_in_menu_encodings (dlg->priv->show_in_menu_list);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_encodings_dialog_init (XedEncodingsDialog *dlg)
|
||||
{
|
||||
GtkWidget *content;
|
||||
GtkCellRenderer *cell_renderer;
|
||||
GtkTreeModel *sort_model;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkTreeIter parent_iter;
|
||||
GtkTreeSelection *selection;
|
||||
const XedEncoding *enc;
|
||||
GtkWidget *error_widget;
|
||||
int i;
|
||||
gboolean ret;
|
||||
gchar *file;
|
||||
gchar *root_objects[] = {
|
||||
"encodings-dialog-contents",
|
||||
NULL
|
||||
};
|
||||
|
||||
dlg->priv = XED_ENCODINGS_DIALOG_GET_PRIVATE (dlg);
|
||||
|
||||
gtk_dialog_add_buttons (GTK_DIALOG (dlg),
|
||||
GTK_STOCK_CANCEL,
|
||||
GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK,
|
||||
GTK_RESPONSE_OK,
|
||||
GTK_STOCK_HELP,
|
||||
GTK_RESPONSE_HELP,
|
||||
NULL);
|
||||
|
||||
gtk_window_set_title (GTK_WINDOW (dlg), _("Character Encodings"));
|
||||
gtk_window_set_default_size (GTK_WINDOW (dlg), 650, 400);
|
||||
|
||||
/* HIG defaults */
|
||||
gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
|
||||
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
|
||||
2); /* 2 * 5 + 2 = 12 */
|
||||
gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dlg))),
|
||||
5);
|
||||
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dlg))), 6);
|
||||
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dlg),
|
||||
GTK_RESPONSE_OK);
|
||||
|
||||
g_signal_connect (dlg,
|
||||
"response",
|
||||
G_CALLBACK (response_handler),
|
||||
dlg);
|
||||
|
||||
file = xed_dirs_get_ui_file ("xed-encodings-dialog.ui");
|
||||
ret = xed_utils_get_ui_objects (file,
|
||||
root_objects,
|
||||
&error_widget,
|
||||
"encodings-dialog-contents", &content,
|
||||
"add-button", &dlg->priv->add_button,
|
||||
"remove-button", &dlg->priv->remove_button,
|
||||
"available-treeview", &dlg->priv->available_treeview,
|
||||
"displayed-treeview", &dlg->priv->displayed_treeview,
|
||||
NULL);
|
||||
g_free (file);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
gtk_widget_show (error_widget);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
|
||||
error_widget,
|
||||
TRUE, TRUE, 0);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (error_widget), 5);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
|
||||
content, TRUE, TRUE, 0);
|
||||
g_object_unref (content);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (content), 5);
|
||||
|
||||
g_signal_connect (dlg->priv->add_button,
|
||||
"clicked",
|
||||
G_CALLBACK (add_button_clicked_callback),
|
||||
dlg);
|
||||
g_signal_connect (dlg->priv->remove_button,
|
||||
"clicked",
|
||||
G_CALLBACK (remove_button_clicked_callback),
|
||||
dlg);
|
||||
|
||||
/* Tree view of available encodings */
|
||||
dlg->priv->available_liststore = gtk_list_store_new (N_COLUMNS,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_STRING);
|
||||
|
||||
cell_renderer = gtk_cell_renderer_text_new ();
|
||||
column = gtk_tree_view_column_new_with_attributes (_("_Description"),
|
||||
cell_renderer,
|
||||
"text", COLUMN_NAME,
|
||||
NULL);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->priv->available_treeview),
|
||||
column);
|
||||
gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
|
||||
|
||||
cell_renderer = gtk_cell_renderer_text_new ();
|
||||
column = gtk_tree_view_column_new_with_attributes (_("_Encoding"),
|
||||
cell_renderer,
|
||||
"text",
|
||||
COLUMN_CHARSET,
|
||||
NULL);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->priv->available_treeview),
|
||||
column);
|
||||
gtk_tree_view_column_set_sort_column_id (column, COLUMN_CHARSET);
|
||||
|
||||
/* Add the data */
|
||||
i = 0;
|
||||
while ((enc = xed_encoding_get_from_index (i)) != NULL)
|
||||
{
|
||||
gtk_list_store_append (dlg->priv->available_liststore,
|
||||
&parent_iter);
|
||||
gtk_list_store_set (dlg->priv->available_liststore,
|
||||
&parent_iter,
|
||||
COLUMN_CHARSET,
|
||||
xed_encoding_get_charset (enc),
|
||||
COLUMN_NAME,
|
||||
xed_encoding_get_name (enc), -1);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
/* Sort model */
|
||||
sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (dlg->priv->available_liststore));
|
||||
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
|
||||
COLUMN_NAME,
|
||||
GTK_SORT_ASCENDING);
|
||||
|
||||
gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->priv->available_treeview),
|
||||
sort_model);
|
||||
g_object_unref (G_OBJECT (dlg->priv->available_liststore));
|
||||
g_object_unref (G_OBJECT (sort_model));
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->priv->available_treeview));
|
||||
gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
|
||||
GTK_SELECTION_MULTIPLE);
|
||||
|
||||
available_selection_changed_callback (selection, dlg);
|
||||
g_signal_connect (selection,
|
||||
"changed",
|
||||
G_CALLBACK (available_selection_changed_callback),
|
||||
dlg);
|
||||
|
||||
/* Tree view of selected encodings */
|
||||
dlg->priv->displayed_liststore = gtk_list_store_new (N_COLUMNS,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_STRING);
|
||||
|
||||
cell_renderer = gtk_cell_renderer_text_new ();
|
||||
column = gtk_tree_view_column_new_with_attributes (_("_Description"),
|
||||
cell_renderer,
|
||||
"text", COLUMN_NAME,
|
||||
NULL);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->priv->displayed_treeview),
|
||||
column);
|
||||
gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
|
||||
|
||||
cell_renderer = gtk_cell_renderer_text_new ();
|
||||
column = gtk_tree_view_column_new_with_attributes (_("_Encoding"),
|
||||
cell_renderer,
|
||||
"text",
|
||||
COLUMN_CHARSET,
|
||||
NULL);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->priv->displayed_treeview),
|
||||
column);
|
||||
gtk_tree_view_column_set_sort_column_id (column, COLUMN_CHARSET);
|
||||
|
||||
/* Add the data */
|
||||
init_shown_in_menu_tree_model (dlg);
|
||||
|
||||
/* Sort model */
|
||||
sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (dlg->priv->displayed_liststore));
|
||||
|
||||
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE
|
||||
(sort_model), COLUMN_NAME,
|
||||
GTK_SORT_ASCENDING);
|
||||
|
||||
gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->priv->displayed_treeview),
|
||||
sort_model);
|
||||
g_object_unref (G_OBJECT (sort_model));
|
||||
g_object_unref (G_OBJECT (dlg->priv->displayed_liststore));
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dlg->priv->displayed_treeview));
|
||||
gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
|
||||
GTK_SELECTION_MULTIPLE);
|
||||
|
||||
displayed_selection_changed_callback (selection, dlg);
|
||||
g_signal_connect (selection,
|
||||
"changed",
|
||||
G_CALLBACK (displayed_selection_changed_callback),
|
||||
dlg);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
xed_encodings_dialog_new (void)
|
||||
{
|
||||
GtkWidget *dlg;
|
||||
|
||||
dlg = GTK_WIDGET (g_object_new (XED_TYPE_ENCODINGS_DIALOG, NULL));
|
||||
|
||||
return dlg;
|
||||
}
|
||||
|
||||
86
xed/dialogs/xed-encodings-dialog.h
Executable file
86
xed/dialogs/xed-encodings-dialog.h
Executable file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* xed-encodings-dialog.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2003-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2003-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_ENCODINGS_DIALOG_H__
|
||||
#define __XED_ENCODINGS_DIALOG_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_ENCODINGS_DIALOG (xed_encodings_dialog_get_type())
|
||||
#define XED_ENCODINGS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_ENCODINGS_DIALOG, XedEncodingsDialog))
|
||||
#define XED_ENCODINGS_DIALOG_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_ENCODINGS_DIALOG, XedEncodingsDialog const))
|
||||
#define XED_ENCODINGS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_ENCODINGS_DIALOG, XedEncodingsDialogClass))
|
||||
#define XED_IS_ENCODINGS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_ENCODINGS_DIALOG))
|
||||
#define XED_IS_ENCODINGS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_ENCODINGS_DIALOG))
|
||||
#define XED_ENCODINGS_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_ENCODINGS_DIALOG, XedEncodingsDialogClass))
|
||||
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedEncodingsDialogPrivate XedEncodingsDialogPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedEncodingsDialog XedEncodingsDialog;
|
||||
|
||||
struct _XedEncodingsDialog
|
||||
{
|
||||
GtkDialog dialog;
|
||||
|
||||
/*< private > */
|
||||
XedEncodingsDialogPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedEncodingsDialogClass XedEncodingsDialogClass;
|
||||
|
||||
struct _XedEncodingsDialogClass
|
||||
{
|
||||
GtkDialogClass parent_class;
|
||||
};
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_encodings_dialog_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget *xed_encodings_dialog_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_ENCODINGS_DIALOG_H__ */
|
||||
|
||||
255
xed/dialogs/xed-encodings-dialog.ui
Executable file
255
xed/dialogs/xed-encodings-dialog.ui
Executable file
@@ -0,0 +1,255 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*- mode: xml -*-->
|
||||
<interface>
|
||||
<object class="GtkDialog" id="encodings-dialog">
|
||||
<property name="width_request">650</property>
|
||||
<property name="height_request">400</property>
|
||||
<property name="title" translatable="yes">Character encodings</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkVBox" id="dialog-vbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkHButtonBox" id="dialog-action_area3">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="helpbutton1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-help</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="closebutton1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="encodings-dialog-contents">
|
||||
<property name="border_width">6</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox6">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="available-label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">A_vailable encodings:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">available-treeview</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="available-treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">True</property>
|
||||
<property name="rules_hint">True</property>
|
||||
<property name="reorderable">False</property>
|
||||
<property name="enable_search">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox6">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="add-button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-add</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox7">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="displayed-label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">E_ncodings shown in menu:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">displayed-treeview</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="displayed-treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">True</property>
|
||||
<property name="rules_hint">True</property>
|
||||
<property name="reorderable">False</property>
|
||||
<property name="enable_search">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox8">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="remove-button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-remove</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<action-widgets>
|
||||
<action-widget response="-11">helpbutton1</action-widget>
|
||||
<action-widget response="-6">closebutton1</action-widget>
|
||||
<action-widget response="-5">button1</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
</interface>
|
||||
1191
xed/dialogs/xed-preferences-dialog.c
Executable file
1191
xed/dialogs/xed-preferences-dialog.c
Executable file
File diff suppressed because it is too large
Load Diff
87
xed/dialogs/xed-preferences-dialog.h
Executable file
87
xed/dialogs/xed-preferences-dialog.h
Executable file
@@ -0,0 +1,87 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* xed-preferences-dialog.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2001-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2003. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_PREFERENCES_DIALOG_H__
|
||||
#define __XED_PREFERENCES_DIALOG_H__
|
||||
|
||||
#include "xed-window.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_PREFERENCES_DIALOG (xed_preferences_dialog_get_type())
|
||||
#define XED_PREFERENCES_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_PREFERENCES_DIALOG, XedPreferencesDialog))
|
||||
#define XED_PREFERENCES_DIALOG_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_PREFERENCES_DIALOG, XedPreferencesDialog const))
|
||||
#define XED_PREFERENCES_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_PREFERENCES_DIALOG, XedPreferencesDialogClass))
|
||||
#define XED_IS_PREFERENCES_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_PREFERENCES_DIALOG))
|
||||
#define XED_IS_PREFERENCES_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_PREFERENCES_DIALOG))
|
||||
#define XED_PREFERENCES_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_PREFERENCES_DIALOG, XedPreferencesDialogClass))
|
||||
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedPreferencesDialogPrivate XedPreferencesDialogPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedPreferencesDialog XedPreferencesDialog;
|
||||
|
||||
struct _XedPreferencesDialog
|
||||
{
|
||||
GtkDialog dialog;
|
||||
|
||||
/*< private > */
|
||||
XedPreferencesDialogPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedPreferencesDialogClass XedPreferencesDialogClass;
|
||||
|
||||
struct _XedPreferencesDialogClass
|
||||
{
|
||||
GtkDialogClass parent_class;
|
||||
};
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_preferences_dialog_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void xed_show_preferences_dialog (XedWindow *parent);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_PREFERENCES_DIALOG_H__ */
|
||||
|
||||
1106
xed/dialogs/xed-preferences-dialog.ui
Executable file
1106
xed/dialogs/xed-preferences-dialog.ui
Executable file
File diff suppressed because it is too large
Load Diff
654
xed/dialogs/xed-search-dialog.c
Executable file
654
xed/dialogs/xed-search-dialog.c
Executable file
@@ -0,0 +1,654 @@
|
||||
/*
|
||||
* xed-search-dialog.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include "xed-search-dialog.h"
|
||||
#include "xed-history-entry.h"
|
||||
#include "xed-utils.h"
|
||||
#include "xed-marshal.h"
|
||||
#include "xed-dirs.h"
|
||||
|
||||
#define XED_SEARCH_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
|
||||
XED_TYPE_SEARCH_DIALOG, \
|
||||
XedSearchDialogPrivate))
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
SHOW_REPLACE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint dialog_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
struct _XedSearchDialogPrivate
|
||||
{
|
||||
gboolean show_replace;
|
||||
|
||||
GtkWidget *table;
|
||||
GtkWidget *search_label;
|
||||
GtkWidget *search_entry;
|
||||
GtkWidget *search_text_entry;
|
||||
GtkWidget *replace_label;
|
||||
GtkWidget *replace_entry;
|
||||
GtkWidget *replace_text_entry;
|
||||
GtkWidget *match_case_checkbutton;
|
||||
GtkWidget *entire_word_checkbutton;
|
||||
GtkWidget *backwards_checkbutton;
|
||||
GtkWidget *wrap_around_checkbutton;
|
||||
GtkWidget *parse_escapes_checkbutton;
|
||||
GtkWidget *find_button;
|
||||
GtkWidget *replace_button;
|
||||
GtkWidget *replace_all_button;
|
||||
|
||||
gboolean ui_error;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(XedSearchDialog, xed_search_dialog, GTK_TYPE_DIALOG)
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_SHOW_REPLACE
|
||||
};
|
||||
|
||||
static void
|
||||
xed_search_dialog_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedSearchDialog *dlg = XED_SEARCH_DIALOG (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SHOW_REPLACE:
|
||||
xed_search_dialog_set_show_replace (dlg,
|
||||
g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_search_dialog_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedSearchDialog *dlg = XED_SEARCH_DIALOG (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SHOW_REPLACE:
|
||||
g_value_set_boolean (value, dlg->priv->show_replace);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xed_search_dialog_present_with_time (XedSearchDialog *dialog,
|
||||
guint32 timestamp)
|
||||
{
|
||||
g_return_if_fail (XED_SEARCH_DIALOG (dialog));
|
||||
|
||||
gtk_window_present_with_time (GTK_WINDOW (dialog), timestamp);
|
||||
|
||||
gtk_widget_grab_focus (dialog->priv->search_text_entry);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
show_replace (XedSearchDialog *dlg)
|
||||
{
|
||||
xed_search_dialog_set_show_replace (dlg, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
xed_search_dialog_class_init (XedSearchDialogClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkBindingSet *binding_set;
|
||||
|
||||
object_class->set_property = xed_search_dialog_set_property;
|
||||
object_class->get_property = xed_search_dialog_get_property;
|
||||
|
||||
klass->show_replace = show_replace;
|
||||
|
||||
dialog_signals[SHOW_REPLACE] =
|
||||
g_signal_new ("show_replace",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
G_STRUCT_OFFSET (XedSearchDialogClass, show_replace),
|
||||
NULL, NULL,
|
||||
xed_marshal_BOOLEAN__NONE,
|
||||
G_TYPE_BOOLEAN, 0);
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SHOW_REPLACE,
|
||||
g_param_spec_boolean ("show-replace",
|
||||
"Show Replace",
|
||||
"Whether the dialog is used for Search&Replace",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (XedSearchDialogPrivate));
|
||||
|
||||
binding_set = gtk_binding_set_by_class (klass);
|
||||
|
||||
/* Note: we cannot use the keyval/modifier associated with the
|
||||
* GTK_STOCK_FIND_AND_REPLACE stock item since MATE HIG suggests Ctrl+h
|
||||
* for Replace while gtk+ uses Ctrl+r */
|
||||
gtk_binding_entry_add_signal (binding_set, GDK_KEY_h, GDK_CONTROL_MASK, "show_replace", 0);
|
||||
gtk_binding_entry_add_signal (binding_set, GDK_KEY_H, GDK_CONTROL_MASK, "show_replace", 0);
|
||||
}
|
||||
|
||||
static void
|
||||
insert_text_handler (GtkEditable *editable,
|
||||
const gchar *text,
|
||||
gint length,
|
||||
gint *position,
|
||||
gpointer data)
|
||||
{
|
||||
static gboolean insert_text = FALSE;
|
||||
gchar *escaped_text;
|
||||
gint new_len;
|
||||
|
||||
/* To avoid recursive behavior */
|
||||
if (insert_text)
|
||||
return;
|
||||
|
||||
escaped_text = xed_utils_escape_search_text (text);
|
||||
|
||||
new_len = strlen (escaped_text);
|
||||
|
||||
if (new_len == length)
|
||||
{
|
||||
g_free (escaped_text);
|
||||
return;
|
||||
}
|
||||
|
||||
insert_text = TRUE;
|
||||
|
||||
g_signal_stop_emission_by_name (editable, "insert_text");
|
||||
|
||||
gtk_editable_insert_text (editable, escaped_text, new_len, position);
|
||||
|
||||
insert_text = FALSE;
|
||||
|
||||
g_free (escaped_text);
|
||||
}
|
||||
|
||||
static void
|
||||
search_text_entry_changed (GtkEditable *editable,
|
||||
XedSearchDialog *dialog)
|
||||
{
|
||||
const gchar *search_string;
|
||||
|
||||
search_string = gtk_entry_get_text (GTK_ENTRY (editable));
|
||||
g_return_if_fail (search_string != NULL);
|
||||
|
||||
if (*search_string != '\0')
|
||||
{
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
|
||||
XED_SEARCH_DIALOG_FIND_RESPONSE, TRUE);
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
|
||||
XED_SEARCH_DIALOG_REPLACE_ALL_RESPONSE, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
|
||||
XED_SEARCH_DIALOG_FIND_RESPONSE, FALSE);
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
|
||||
XED_SEARCH_DIALOG_REPLACE_RESPONSE, FALSE);
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
|
||||
XED_SEARCH_DIALOG_REPLACE_ALL_RESPONSE, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
response_handler (XedSearchDialog *dialog,
|
||||
gint response_id,
|
||||
gpointer data)
|
||||
{
|
||||
const gchar *str;
|
||||
|
||||
switch (response_id)
|
||||
{
|
||||
case XED_SEARCH_DIALOG_REPLACE_RESPONSE:
|
||||
case XED_SEARCH_DIALOG_REPLACE_ALL_RESPONSE:
|
||||
str = gtk_entry_get_text (GTK_ENTRY (dialog->priv->replace_text_entry));
|
||||
if (*str != '\0')
|
||||
{
|
||||
gchar *text;
|
||||
|
||||
text = xed_utils_unescape_search_text (str);
|
||||
xed_history_entry_prepend_text
|
||||
(XED_HISTORY_ENTRY (dialog->priv->replace_entry),
|
||||
text);
|
||||
|
||||
g_free (text);
|
||||
}
|
||||
/* fall through, so that we also save the find entry */
|
||||
case XED_SEARCH_DIALOG_FIND_RESPONSE:
|
||||
str = gtk_entry_get_text (GTK_ENTRY (dialog->priv->search_text_entry));
|
||||
if (*str != '\0')
|
||||
{
|
||||
gchar *text;
|
||||
|
||||
text = xed_utils_unescape_search_text (str);
|
||||
xed_history_entry_prepend_text
|
||||
(XED_HISTORY_ENTRY (dialog->priv->search_entry),
|
||||
text);
|
||||
|
||||
g_free (text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
show_replace_widgets (XedSearchDialog *dlg,
|
||||
gboolean show_replace)
|
||||
{
|
||||
if (show_replace)
|
||||
{
|
||||
gtk_widget_show (dlg->priv->replace_label);
|
||||
gtk_widget_show (dlg->priv->replace_entry);
|
||||
gtk_widget_show (dlg->priv->replace_all_button);
|
||||
gtk_widget_show (dlg->priv->replace_button);
|
||||
|
||||
gtk_table_set_row_spacings (GTK_TABLE (dlg->priv->table), 12);
|
||||
|
||||
gtk_window_set_title (GTK_WINDOW (dlg), _("Replace"));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_hide (dlg->priv->replace_label);
|
||||
gtk_widget_hide (dlg->priv->replace_entry);
|
||||
gtk_widget_hide (dlg->priv->replace_all_button);
|
||||
gtk_widget_hide (dlg->priv->replace_button);
|
||||
|
||||
gtk_table_set_row_spacings (GTK_TABLE (dlg->priv->table), 0);
|
||||
|
||||
gtk_window_set_title (GTK_WINDOW (dlg), _("Find"));
|
||||
}
|
||||
|
||||
gtk_widget_show (dlg->priv->find_button);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_search_dialog_init (XedSearchDialog *dlg)
|
||||
{
|
||||
GtkWidget *content;
|
||||
GtkWidget *error_widget;
|
||||
gboolean ret;
|
||||
gchar *file;
|
||||
gchar *root_objects[] = {
|
||||
"search_dialog_content",
|
||||
NULL
|
||||
};
|
||||
|
||||
dlg->priv = XED_SEARCH_DIALOG_GET_PRIVATE (dlg);
|
||||
|
||||
gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
|
||||
gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
|
||||
|
||||
gtk_dialog_add_buttons (GTK_DIALOG (dlg),
|
||||
GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
|
||||
NULL);
|
||||
|
||||
/* HIG defaults */
|
||||
gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
|
||||
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
|
||||
2); /* 2 * 5 + 2 = 12 */
|
||||
gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dlg))),
|
||||
5);
|
||||
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dlg))),
|
||||
6);
|
||||
|
||||
file = xed_dirs_get_ui_file ("xed-search-dialog.ui");
|
||||
ret = xed_utils_get_ui_objects (file,
|
||||
root_objects,
|
||||
&error_widget,
|
||||
"search_dialog_content", &content,
|
||||
"table", &dlg->priv->table,
|
||||
"search_label", &dlg->priv->search_label,
|
||||
"replace_with_label", &dlg->priv->replace_label,
|
||||
"match_case_checkbutton", &dlg->priv->match_case_checkbutton,
|
||||
"entire_word_checkbutton", &dlg->priv->entire_word_checkbutton,
|
||||
"search_backwards_checkbutton", &dlg->priv->backwards_checkbutton,
|
||||
"wrap_around_checkbutton", &dlg->priv->wrap_around_checkbutton,
|
||||
"parse_escapes_checkbutton", &dlg->priv->parse_escapes_checkbutton,
|
||||
NULL);
|
||||
g_free (file);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
gtk_widget_show (error_widget);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
|
||||
error_widget,
|
||||
TRUE, TRUE, 0);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (error_widget),
|
||||
5);
|
||||
|
||||
dlg->priv->ui_error = TRUE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
dlg->priv->search_entry = xed_history_entry_new ("history-search-for",
|
||||
TRUE);
|
||||
gtk_widget_set_size_request (dlg->priv->search_entry, 300, -1);
|
||||
xed_history_entry_set_escape_func
|
||||
(XED_HISTORY_ENTRY (dlg->priv->search_entry),
|
||||
(XedHistoryEntryEscapeFunc) xed_utils_escape_search_text);
|
||||
|
||||
dlg->priv->search_text_entry = xed_history_entry_get_entry
|
||||
(XED_HISTORY_ENTRY (dlg->priv->search_entry));
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (dlg->priv->search_text_entry),
|
||||
TRUE);
|
||||
gtk_widget_show (dlg->priv->search_entry);
|
||||
gtk_table_attach_defaults (GTK_TABLE (dlg->priv->table),
|
||||
dlg->priv->search_entry,
|
||||
1, 2, 0, 1);
|
||||
|
||||
dlg->priv->replace_entry = xed_history_entry_new ("history-replace-with",
|
||||
TRUE);
|
||||
xed_history_entry_set_escape_func
|
||||
(XED_HISTORY_ENTRY (dlg->priv->replace_entry),
|
||||
(XedHistoryEntryEscapeFunc) xed_utils_escape_search_text);
|
||||
|
||||
dlg->priv->replace_text_entry = xed_history_entry_get_entry
|
||||
(XED_HISTORY_ENTRY (dlg->priv->replace_entry));
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (dlg->priv->replace_text_entry),
|
||||
TRUE);
|
||||
gtk_widget_show (dlg->priv->replace_entry);
|
||||
gtk_table_attach_defaults (GTK_TABLE (dlg->priv->table),
|
||||
dlg->priv->replace_entry,
|
||||
1, 2, 1, 2);
|
||||
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (dlg->priv->search_label),
|
||||
dlg->priv->search_entry);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (dlg->priv->replace_label),
|
||||
dlg->priv->replace_entry);
|
||||
|
||||
dlg->priv->find_button = gtk_button_new_from_stock (GTK_STOCK_FIND);
|
||||
dlg->priv->replace_all_button = gtk_button_new_with_mnemonic (_("Replace _All"));
|
||||
dlg->priv->replace_button = xed_gtk_button_new_with_stock_icon (_("_Replace"),
|
||||
GTK_STOCK_FIND_AND_REPLACE);
|
||||
|
||||
gtk_dialog_add_action_widget (GTK_DIALOG (dlg),
|
||||
dlg->priv->replace_all_button,
|
||||
XED_SEARCH_DIALOG_REPLACE_ALL_RESPONSE);
|
||||
gtk_dialog_add_action_widget (GTK_DIALOG (dlg),
|
||||
dlg->priv->replace_button,
|
||||
XED_SEARCH_DIALOG_REPLACE_RESPONSE);
|
||||
gtk_dialog_add_action_widget (GTK_DIALOG (dlg),
|
||||
dlg->priv->find_button,
|
||||
XED_SEARCH_DIALOG_FIND_RESPONSE);
|
||||
g_object_set (G_OBJECT (dlg->priv->find_button),
|
||||
"can-default", TRUE,
|
||||
NULL);
|
||||
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dlg),
|
||||
XED_SEARCH_DIALOG_FIND_RESPONSE);
|
||||
|
||||
/* insensitive by default */
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dlg),
|
||||
XED_SEARCH_DIALOG_FIND_RESPONSE,
|
||||
FALSE);
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dlg),
|
||||
XED_SEARCH_DIALOG_REPLACE_RESPONSE,
|
||||
FALSE);
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dlg),
|
||||
XED_SEARCH_DIALOG_REPLACE_ALL_RESPONSE,
|
||||
FALSE);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
|
||||
content, FALSE, FALSE, 0);
|
||||
g_object_unref (content);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (content), 5);
|
||||
|
||||
g_signal_connect (dlg->priv->search_text_entry,
|
||||
"insert_text",
|
||||
G_CALLBACK (insert_text_handler),
|
||||
NULL);
|
||||
g_signal_connect (dlg->priv->replace_text_entry,
|
||||
"insert_text",
|
||||
G_CALLBACK (insert_text_handler),
|
||||
NULL);
|
||||
g_signal_connect (dlg->priv->search_text_entry,
|
||||
"changed",
|
||||
G_CALLBACK (search_text_entry_changed),
|
||||
dlg);
|
||||
|
||||
g_signal_connect (dlg,
|
||||
"response",
|
||||
G_CALLBACK (response_handler),
|
||||
NULL);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
xed_search_dialog_new (GtkWindow *parent,
|
||||
gboolean show_replace)
|
||||
{
|
||||
XedSearchDialog *dlg;
|
||||
|
||||
dlg = g_object_new (XED_TYPE_SEARCH_DIALOG,
|
||||
"show-replace", show_replace,
|
||||
NULL);
|
||||
|
||||
if (parent != NULL)
|
||||
{
|
||||
gtk_window_set_transient_for (GTK_WINDOW (dlg),
|
||||
parent);
|
||||
|
||||
gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg),
|
||||
TRUE);
|
||||
}
|
||||
|
||||
return GTK_WIDGET (dlg);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_search_dialog_get_show_replace (XedSearchDialog *dialog)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_SEARCH_DIALOG (dialog), FALSE);
|
||||
|
||||
return dialog->priv->show_replace;
|
||||
}
|
||||
|
||||
void
|
||||
xed_search_dialog_set_show_replace (XedSearchDialog *dialog,
|
||||
gboolean show_replace)
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCH_DIALOG (dialog));
|
||||
|
||||
if (dialog->priv->ui_error)
|
||||
return;
|
||||
|
||||
dialog->priv->show_replace = show_replace != FALSE;
|
||||
show_replace_widgets (dialog, dialog->priv->show_replace);
|
||||
|
||||
g_object_notify (G_OBJECT (dialog), "show-replace");
|
||||
}
|
||||
|
||||
void
|
||||
xed_search_dialog_set_search_text (XedSearchDialog *dialog,
|
||||
const gchar *text)
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCH_DIALOG (dialog));
|
||||
g_return_if_fail (text != NULL);
|
||||
|
||||
gtk_entry_set_text (GTK_ENTRY (dialog->priv->search_text_entry),
|
||||
text);
|
||||
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
|
||||
XED_SEARCH_DIALOG_FIND_RESPONSE,
|
||||
(text != '\0'));
|
||||
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
|
||||
XED_SEARCH_DIALOG_REPLACE_ALL_RESPONSE,
|
||||
(text != '\0'));
|
||||
}
|
||||
|
||||
/*
|
||||
* The text must be unescaped before searching.
|
||||
*/
|
||||
const gchar *
|
||||
xed_search_dialog_get_search_text (XedSearchDialog *dialog)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_SEARCH_DIALOG (dialog), NULL);
|
||||
|
||||
return gtk_entry_get_text (GTK_ENTRY (dialog->priv->search_text_entry));
|
||||
}
|
||||
|
||||
void
|
||||
xed_search_dialog_set_replace_text (XedSearchDialog *dialog,
|
||||
const gchar *text)
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCH_DIALOG (dialog));
|
||||
g_return_if_fail (text != NULL);
|
||||
|
||||
gtk_entry_set_text (GTK_ENTRY (dialog->priv->replace_text_entry),
|
||||
text);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_search_dialog_get_replace_text (XedSearchDialog *dialog)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_SEARCH_DIALOG (dialog), NULL);
|
||||
|
||||
return gtk_entry_get_text (GTK_ENTRY (dialog->priv->replace_text_entry));
|
||||
}
|
||||
|
||||
void
|
||||
xed_search_dialog_set_match_case (XedSearchDialog *dialog,
|
||||
gboolean match_case)
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCH_DIALOG (dialog));
|
||||
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->match_case_checkbutton),
|
||||
match_case);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_search_dialog_get_match_case (XedSearchDialog *dialog)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_SEARCH_DIALOG (dialog), FALSE);
|
||||
|
||||
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->match_case_checkbutton));
|
||||
}
|
||||
|
||||
void
|
||||
xed_search_dialog_set_entire_word (XedSearchDialog *dialog,
|
||||
gboolean entire_word)
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCH_DIALOG (dialog));
|
||||
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->entire_word_checkbutton),
|
||||
entire_word);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_search_dialog_get_entire_word (XedSearchDialog *dialog)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_SEARCH_DIALOG (dialog), FALSE);
|
||||
|
||||
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->entire_word_checkbutton));
|
||||
}
|
||||
|
||||
void
|
||||
xed_search_dialog_set_backwards (XedSearchDialog *dialog,
|
||||
gboolean backwards)
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCH_DIALOG (dialog));
|
||||
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->backwards_checkbutton),
|
||||
backwards);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_search_dialog_get_backwards (XedSearchDialog *dialog)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_SEARCH_DIALOG (dialog), FALSE);
|
||||
|
||||
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->backwards_checkbutton));
|
||||
}
|
||||
|
||||
void
|
||||
xed_search_dialog_set_wrap_around (XedSearchDialog *dialog,
|
||||
gboolean wrap_around)
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCH_DIALOG (dialog));
|
||||
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->wrap_around_checkbutton),
|
||||
wrap_around);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_search_dialog_get_wrap_around (XedSearchDialog *dialog)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_SEARCH_DIALOG (dialog), FALSE);
|
||||
|
||||
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->wrap_around_checkbutton));
|
||||
}
|
||||
|
||||
void
|
||||
xed_search_dialog_set_parse_escapes (XedSearchDialog *dialog,
|
||||
gboolean parse_escapes)
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCH_DIALOG (dialog));
|
||||
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->parse_escapes_checkbutton),
|
||||
parse_escapes);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_search_dialog_get_parse_escapes (XedSearchDialog *dialog)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_SEARCH_DIALOG (dialog), FALSE);
|
||||
|
||||
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->parse_escapes_checkbutton));
|
||||
}
|
||||
133
xed/dialogs/xed-search-dialog.h
Executable file
133
xed/dialogs/xed-search-dialog.h
Executable file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* xed-search-dialog.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_SEARCH_DIALOG_H__
|
||||
#define __XED_SEARCH_DIALOG_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_SEARCH_DIALOG (xed_search_dialog_get_type())
|
||||
#define XED_SEARCH_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_SEARCH_DIALOG, XedSearchDialog))
|
||||
#define XED_SEARCH_DIALOG_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_SEARCH_DIALOG, XedSearchDialog const))
|
||||
#define XED_SEARCH_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_SEARCH_DIALOG, XedSearchDialogClass))
|
||||
#define XED_IS_SEARCH_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_SEARCH_DIALOG))
|
||||
#define XED_IS_SEARCH_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_SEARCH_DIALOG))
|
||||
#define XED_SEARCH_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_SEARCH_DIALOG, XedSearchDialogClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedSearchDialogPrivate XedSearchDialogPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedSearchDialog XedSearchDialog;
|
||||
|
||||
struct _XedSearchDialog
|
||||
{
|
||||
GtkDialog dialog;
|
||||
|
||||
/*< private > */
|
||||
XedSearchDialogPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedSearchDialogClass XedSearchDialogClass;
|
||||
|
||||
struct _XedSearchDialogClass
|
||||
{
|
||||
GtkDialogClass parent_class;
|
||||
|
||||
/* Key bindings */
|
||||
gboolean (* show_replace) (XedSearchDialog *dlg);
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
XED_SEARCH_DIALOG_FIND_RESPONSE = 100,
|
||||
XED_SEARCH_DIALOG_REPLACE_RESPONSE,
|
||||
XED_SEARCH_DIALOG_REPLACE_ALL_RESPONSE
|
||||
};
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_search_dialog_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget *xed_search_dialog_new (GtkWindow *parent,
|
||||
gboolean show_replace);
|
||||
|
||||
void xed_search_dialog_present_with_time (XedSearchDialog *dialog,
|
||||
guint32 timestamp);
|
||||
|
||||
gboolean xed_search_dialog_get_show_replace (XedSearchDialog *dialog);
|
||||
|
||||
void xed_search_dialog_set_show_replace (XedSearchDialog *dialog,
|
||||
gboolean show_replace);
|
||||
|
||||
|
||||
void xed_search_dialog_set_search_text (XedSearchDialog *dialog,
|
||||
const gchar *text);
|
||||
const gchar *xed_search_dialog_get_search_text (XedSearchDialog *dialog);
|
||||
|
||||
void xed_search_dialog_set_replace_text (XedSearchDialog *dialog,
|
||||
const gchar *text);
|
||||
const gchar *xed_search_dialog_get_replace_text (XedSearchDialog *dialog);
|
||||
|
||||
void xed_search_dialog_set_match_case (XedSearchDialog *dialog,
|
||||
gboolean match_case);
|
||||
gboolean xed_search_dialog_get_match_case (XedSearchDialog *dialog);
|
||||
|
||||
void xed_search_dialog_set_entire_word (XedSearchDialog *dialog,
|
||||
gboolean entire_word);
|
||||
gboolean xed_search_dialog_get_entire_word (XedSearchDialog *dialog);
|
||||
|
||||
void xed_search_dialog_set_backwards (XedSearchDialog *dialog,
|
||||
gboolean backwards);
|
||||
gboolean xed_search_dialog_get_backwards (XedSearchDialog *dialog);
|
||||
|
||||
void xed_search_dialog_set_wrap_around (XedSearchDialog *dialog,
|
||||
gboolean wrap_around);
|
||||
gboolean xed_search_dialog_get_wrap_around (XedSearchDialog *dialog);
|
||||
|
||||
|
||||
void xed_search_dialog_set_parse_escapes (XedSearchDialog *dialog,
|
||||
gboolean parse_escapes);
|
||||
gboolean xed_search_dialog_get_parse_escapes (XedSearchDialog *dialog);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_SEARCH_DIALOG_H__ */
|
||||
272
xed/dialogs/xed-search-dialog.ui
Executable file
272
xed/dialogs/xed-search-dialog.ui
Executable file
@@ -0,0 +1,272 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*- mode: xml -*-->
|
||||
<interface>
|
||||
<object class="GtkDialog" id="dialog">
|
||||
<property name="title" translatable="yes">Replace</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="resizable">False</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
<property name="urgency_hint">False</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">8</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkHButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="close_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="replace_all_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Replace All</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="replace_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Replace</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="find_next_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-find</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkVBox" id="search_dialog_content">
|
||||
<property name="border_width">5</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">18</property>
|
||||
<child>
|
||||
<object class="GtkTable" id="table">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">2</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<property name="column_spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="search_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Search for: </property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"/>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="replace_with_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Replace _with: </property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"/>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="match_case_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Match case</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">False</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="entire_word_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Match _entire word only</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">False</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="search_backwards_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Search _backwards</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">False</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="wrap_around_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Wrap around</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="parse_escapes_checkbutton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Parse escape sequences (e.g. \n)</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<action-widgets>
|
||||
<action-widget response="0">close_button</action-widget>
|
||||
<action-widget response="0">replace_all_button</action-widget>
|
||||
<action-widget response="0">replace_button</action-widget>
|
||||
<action-widget response="0">find_next_button</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
</interface>
|
||||
39
xed/smclient/Makefile.am
Normal file
39
xed/smclient/Makefile.am
Normal file
@@ -0,0 +1,39 @@
|
||||
platform_defines = -DEGG_SM_CLIENT_BACKEND_XSMP
|
||||
platform_libs = libeggdesktopfile.la
|
||||
platform_ltlibraries = libeggdesktopfile.la
|
||||
platform_sources = eggsmclient-xsmp.c
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-DG_LOG_DOMAIN=\""EggSMClient"\" \
|
||||
$(XED_CFLAGS) \
|
||||
$(platform_defines) \
|
||||
$(EGG_SMCLIENT_CFLAGS)
|
||||
|
||||
noinst_LTLIBRARIES = \
|
||||
libeggsmclient.la \
|
||||
$(platform_ltlibraries)
|
||||
|
||||
libeggsmclient_la_LIBADD = \
|
||||
$(EGG_SMCLIENT_LIBS) \
|
||||
$(platform_libs)
|
||||
|
||||
libeggsmclient_la_LDFLAGS = \
|
||||
$(platform_ldflags)
|
||||
|
||||
libeggsmclient_la_SOURCES = \
|
||||
eggsmclient.c \
|
||||
eggsmclient.h \
|
||||
eggsmclient-private.h \
|
||||
$(platform_sources)
|
||||
|
||||
libeggdesktopfile_la_LIBADD = \
|
||||
$(EGG_LIBS)
|
||||
|
||||
libeggdesktopfile_la_SOURCES = \
|
||||
eggdesktopfile.c \
|
||||
eggdesktopfile.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
eggsmclient-xsmp.c
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
1502
xed/smclient/eggdesktopfile.c
Normal file
1502
xed/smclient/eggdesktopfile.c
Normal file
File diff suppressed because it is too large
Load Diff
160
xed/smclient/eggdesktopfile.h
Normal file
160
xed/smclient/eggdesktopfile.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/* eggdesktopfile.h - Freedesktop.Org Desktop Files
|
||||
* Copyright (C) 2007 Novell, Inc.
|
||||
*
|
||||
* 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 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; see the file COPYING.LIB. If not,
|
||||
* write to the Free Software Foundation, Inc., 151 Franklin Street,
|
||||
* Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __EGG_DESKTOP_FILE_H__
|
||||
#define __EGG_DESKTOP_FILE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct EggDesktopFile EggDesktopFile;
|
||||
|
||||
typedef enum {
|
||||
EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED,
|
||||
|
||||
EGG_DESKTOP_FILE_TYPE_APPLICATION,
|
||||
EGG_DESKTOP_FILE_TYPE_LINK,
|
||||
EGG_DESKTOP_FILE_TYPE_DIRECTORY
|
||||
} EggDesktopFileType;
|
||||
|
||||
EggDesktopFile *egg_desktop_file_new (const char *desktop_file_path,
|
||||
GError **error);
|
||||
|
||||
EggDesktopFile *egg_desktop_file_new_from_data_dirs (const char *desktop_file_path,
|
||||
GError **error);
|
||||
EggDesktopFile *egg_desktop_file_new_from_dirs (const char *desktop_file_path,
|
||||
const char **search_dirs,
|
||||
GError **error);
|
||||
EggDesktopFile *egg_desktop_file_new_from_key_file (GKeyFile *key_file,
|
||||
const char *source,
|
||||
GError **error);
|
||||
|
||||
void egg_desktop_file_free (EggDesktopFile *desktop_file);
|
||||
|
||||
const char *egg_desktop_file_get_source (EggDesktopFile *desktop_file);
|
||||
|
||||
EggDesktopFileType egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file);
|
||||
|
||||
const char *egg_desktop_file_get_name (EggDesktopFile *desktop_file);
|
||||
const char *egg_desktop_file_get_icon (EggDesktopFile *desktop_file);
|
||||
|
||||
gboolean egg_desktop_file_can_launch (EggDesktopFile *desktop_file,
|
||||
const char *desktop_environment);
|
||||
|
||||
gboolean egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file);
|
||||
gboolean egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file);
|
||||
gboolean egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file);
|
||||
|
||||
char *egg_desktop_file_parse_exec (EggDesktopFile *desktop_file,
|
||||
GSList *documents,
|
||||
GError **error);
|
||||
|
||||
gboolean egg_desktop_file_launch (EggDesktopFile *desktop_file,
|
||||
GSList *documents,
|
||||
GError **error,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
typedef enum {
|
||||
EGG_DESKTOP_FILE_LAUNCH_CLEARENV = 1,
|
||||
EGG_DESKTOP_FILE_LAUNCH_PUTENV,
|
||||
EGG_DESKTOP_FILE_LAUNCH_SCREEN,
|
||||
EGG_DESKTOP_FILE_LAUNCH_WORKSPACE,
|
||||
EGG_DESKTOP_FILE_LAUNCH_DIRECTORY,
|
||||
EGG_DESKTOP_FILE_LAUNCH_TIME,
|
||||
EGG_DESKTOP_FILE_LAUNCH_FLAGS,
|
||||
EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC,
|
||||
EGG_DESKTOP_FILE_LAUNCH_RETURN_PID,
|
||||
EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE,
|
||||
EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE,
|
||||
EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE,
|
||||
EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID
|
||||
} EggDesktopFileLaunchOption;
|
||||
|
||||
/* Standard Keys */
|
||||
#define EGG_DESKTOP_FILE_GROUP "Desktop Entry"
|
||||
|
||||
#define EGG_DESKTOP_FILE_KEY_TYPE "Type"
|
||||
#define EGG_DESKTOP_FILE_KEY_VERSION "Version"
|
||||
#define EGG_DESKTOP_FILE_KEY_NAME "Name"
|
||||
#define EGG_DESKTOP_FILE_KEY_GENERIC_NAME "GenericName"
|
||||
#define EGG_DESKTOP_FILE_KEY_NO_DISPLAY "NoDisplay"
|
||||
#define EGG_DESKTOP_FILE_KEY_COMMENT "Comment"
|
||||
#define EGG_DESKTOP_FILE_KEY_ICON "Icon"
|
||||
#define EGG_DESKTOP_FILE_KEY_HIDDEN "Hidden"
|
||||
#define EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN "OnlyShowIn"
|
||||
#define EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN "NotShowIn"
|
||||
#define EGG_DESKTOP_FILE_KEY_TRY_EXEC "TryExec"
|
||||
#define EGG_DESKTOP_FILE_KEY_EXEC "Exec"
|
||||
#define EGG_DESKTOP_FILE_KEY_PATH "Path"
|
||||
#define EGG_DESKTOP_FILE_KEY_TERMINAL "Terminal"
|
||||
#define EGG_DESKTOP_FILE_KEY_MIME_TYPE "MimeType"
|
||||
#define EGG_DESKTOP_FILE_KEY_CATEGORIES "Categories"
|
||||
#define EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY "StartupNotify"
|
||||
#define EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS "StartupWMClass"
|
||||
#define EGG_DESKTOP_FILE_KEY_URL "URL"
|
||||
|
||||
/* Accessors */
|
||||
gboolean egg_desktop_file_has_key (EggDesktopFile *desktop_file,
|
||||
const char *key,
|
||||
GError **error);
|
||||
char *egg_desktop_file_get_string (EggDesktopFile *desktop_file,
|
||||
const char *key,
|
||||
GError **error) G_GNUC_MALLOC;
|
||||
char *egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file,
|
||||
const char *key,
|
||||
const char *locale,
|
||||
GError **error) G_GNUC_MALLOC;
|
||||
gboolean egg_desktop_file_get_boolean (EggDesktopFile *desktop_file,
|
||||
const char *key,
|
||||
GError **error);
|
||||
double egg_desktop_file_get_numeric (EggDesktopFile *desktop_file,
|
||||
const char *key,
|
||||
GError **error);
|
||||
char **egg_desktop_file_get_string_list (EggDesktopFile *desktop_file,
|
||||
const char *key,
|
||||
gsize *length,
|
||||
GError **error) G_GNUC_MALLOC;
|
||||
char **egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file,
|
||||
const char *key,
|
||||
const char *locale,
|
||||
gsize *length,
|
||||
GError **error) G_GNUC_MALLOC;
|
||||
|
||||
|
||||
/* Errors */
|
||||
#define EGG_DESKTOP_FILE_ERROR egg_desktop_file_error_quark()
|
||||
|
||||
GQuark egg_desktop_file_error_quark (void);
|
||||
|
||||
typedef enum {
|
||||
EGG_DESKTOP_FILE_ERROR_INVALID,
|
||||
EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
|
||||
EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION
|
||||
} EggDesktopFileError;
|
||||
|
||||
/* Global application desktop file */
|
||||
void egg_set_desktop_file (const char *desktop_file_path);
|
||||
void egg_set_desktop_file_without_defaults (const char *desktop_file_path);
|
||||
EggDesktopFile *egg_get_desktop_file (void);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __EGG_DESKTOP_FILE_H__ */
|
||||
42
xed/smclient/eggsmclient-private.h
Normal file
42
xed/smclient/eggsmclient-private.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* eggsmclient-private.h
|
||||
* Copyright (C) 2007 Novell, Inc.
|
||||
*
|
||||
* 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 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __EGG_SM_CLIENT_PRIVATE_H__
|
||||
#define __EGG_SM_CLIENT_PRIVATE_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#if !GTK_CHECK_VERSION (3, 0, 0)
|
||||
#include <gdkconfig.h>
|
||||
#endif
|
||||
#include "eggsmclient.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GKeyFile *egg_sm_client_save_state (EggSMClient *client);
|
||||
void egg_sm_client_quit_requested (EggSMClient *client);
|
||||
void egg_sm_client_quit_cancelled (EggSMClient *client);
|
||||
void egg_sm_client_quit (EggSMClient *client);
|
||||
|
||||
GType egg_sm_client_xsmp_get_type (void);
|
||||
EggSMClient *egg_sm_client_xsmp_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
#endif /* __EGG_SM_CLIENT_PRIVATE_H__ */
|
||||
1384
xed/smclient/eggsmclient-xsmp.c
Normal file
1384
xed/smclient/eggsmclient-xsmp.c
Normal file
File diff suppressed because it is too large
Load Diff
573
xed/smclient/eggsmclient.c
Normal file
573
xed/smclient/eggsmclient.c
Normal file
@@ -0,0 +1,573 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Novell, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "eggsmclient.h"
|
||||
#include "eggsmclient-private.h"
|
||||
|
||||
static void egg_sm_client_debug_handler (const char *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const char *message,
|
||||
gpointer user_data);
|
||||
|
||||
enum {
|
||||
SAVE_STATE,
|
||||
QUIT_REQUESTED,
|
||||
QUIT_CANCELLED,
|
||||
QUIT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
struct _EggSMClientPrivate {
|
||||
GKeyFile *state_file;
|
||||
};
|
||||
|
||||
#define EGG_SM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_SM_CLIENT, EggSMClientPrivate))
|
||||
|
||||
G_DEFINE_TYPE (EggSMClient, egg_sm_client, G_TYPE_OBJECT)
|
||||
|
||||
static EggSMClient *global_client;
|
||||
static EggSMClientMode global_client_mode = EGG_SM_CLIENT_MODE_NORMAL;
|
||||
|
||||
static void
|
||||
egg_sm_client_init (EggSMClient *client)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
egg_sm_client_class_init (EggSMClientClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (EggSMClientPrivate));
|
||||
|
||||
/**
|
||||
* EggSMClient::save_state:
|
||||
* @client: the client
|
||||
* @state_file: a #GKeyFile to save state information into
|
||||
*
|
||||
* Emitted when the session manager has requested that the
|
||||
* application save information about its current state. The
|
||||
* application should save its state into @state_file, and then the
|
||||
* session manager may then restart the application in a future
|
||||
* session and tell it to initialize itself from that state.
|
||||
*
|
||||
* You should not save any data into @state_file's "start group"
|
||||
* (ie, the %NULL group). Instead, applications should save their
|
||||
* data into groups with names that start with the application name,
|
||||
* and libraries that connect to this signal should save their data
|
||||
* into groups with names that start with the library name.
|
||||
*
|
||||
* Alternatively, rather than (or in addition to) using @state_file,
|
||||
* the application can save its state by calling
|
||||
* egg_sm_client_set_restart_command() during the processing of this
|
||||
* signal (eg, to include a list of files to open).
|
||||
**/
|
||||
signals[SAVE_STATE] =
|
||||
g_signal_new ("save_state",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (EggSMClientClass, save_state),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__POINTER,
|
||||
G_TYPE_NONE,
|
||||
1, G_TYPE_POINTER);
|
||||
|
||||
/**
|
||||
* EggSMClient::quit_requested:
|
||||
* @client: the client
|
||||
*
|
||||
* Emitted when the session manager requests that the application
|
||||
* exit (generally because the user is logging out). The application
|
||||
* should decide whether or not it is willing to quit (perhaps after
|
||||
* asking the user what to do with documents that have unsaved
|
||||
* changes) and then call egg_sm_client_will_quit(), passing %TRUE
|
||||
* or %FALSE to give its answer to the session manager. (It does not
|
||||
* need to give an answer before returning from the signal handler;
|
||||
* it can interact with the user asynchronously and then give its
|
||||
* answer later on.) If the application does not connect to this
|
||||
* signal, then #EggSMClient will automatically return %TRUE on its
|
||||
* behalf.
|
||||
*
|
||||
* The application should not save its session state as part of
|
||||
* handling this signal; if the user has requested that the session
|
||||
* be saved when logging out, then ::save_state will be emitted
|
||||
* separately.
|
||||
*
|
||||
* If the application agrees to quit, it should then wait for either
|
||||
* the ::quit_cancelled or ::quit signals to be emitted.
|
||||
**/
|
||||
signals[QUIT_REQUESTED] =
|
||||
g_signal_new ("quit_requested",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (EggSMClientClass, quit_requested),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
/**
|
||||
* EggSMClient::quit_cancelled:
|
||||
* @client: the client
|
||||
*
|
||||
* Emitted when the session manager decides to cancel a logout after
|
||||
* the application has already agreed to quit. After receiving this
|
||||
* signal, the application can go back to what it was doing before
|
||||
* receiving the ::quit_requested signal.
|
||||
**/
|
||||
signals[QUIT_CANCELLED] =
|
||||
g_signal_new ("quit_cancelled",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (EggSMClientClass, quit_cancelled),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
/**
|
||||
* EggSMClient::quit:
|
||||
* @client: the client
|
||||
*
|
||||
* Emitted when the session manager wants the application to quit
|
||||
* (generally because the user is logging out). The application
|
||||
* should exit as soon as possible after receiving this signal; if
|
||||
* it does not, the session manager may choose to forcibly kill it.
|
||||
*
|
||||
* Normally a GUI application would only be sent a ::quit if it
|
||||
* agreed to quit in response to a ::quit_requested signal. However,
|
||||
* this is not guaranteed; in some situations the session manager
|
||||
* may decide to end the session without giving applications a
|
||||
* chance to object.
|
||||
**/
|
||||
signals[QUIT] =
|
||||
g_signal_new ("quit",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (EggSMClientClass, quit),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
}
|
||||
|
||||
static gboolean sm_client_disable = FALSE;
|
||||
static char *sm_client_state_file = NULL;
|
||||
static char *sm_client_id = NULL;
|
||||
static char *sm_config_prefix = NULL;
|
||||
|
||||
static gboolean
|
||||
sm_client_post_parse_func (GOptionContext *context,
|
||||
GOptionGroup *group,
|
||||
gpointer data,
|
||||
GError **error)
|
||||
{
|
||||
EggSMClient *client = egg_sm_client_get ();
|
||||
|
||||
if (sm_client_id == NULL)
|
||||
{
|
||||
const gchar *desktop_autostart_id;
|
||||
|
||||
desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
|
||||
|
||||
if (desktop_autostart_id != NULL)
|
||||
sm_client_id = g_strdup (desktop_autostart_id);
|
||||
}
|
||||
|
||||
/* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
|
||||
* use the same client id. */
|
||||
g_unsetenv ("DESKTOP_AUTOSTART_ID");
|
||||
|
||||
if (EGG_SM_CLIENT_GET_CLASS (client)->startup)
|
||||
EGG_SM_CLIENT_GET_CLASS (client)->startup (client, sm_client_id);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_sm_client_get_option_group:
|
||||
*
|
||||
* Creates a %GOptionGroup containing the session-management-related
|
||||
* options. You should add this group to the application's
|
||||
* %GOptionContext if you want to use #EggSMClient.
|
||||
*
|
||||
* Return value: the %GOptionGroup
|
||||
**/
|
||||
GOptionGroup *
|
||||
egg_sm_client_get_option_group (void)
|
||||
{
|
||||
const GOptionEntry entries[] = {
|
||||
{ "sm-client-disable", 0, 0,
|
||||
G_OPTION_ARG_NONE, &sm_client_disable,
|
||||
N_("Disable connection to session manager"), NULL },
|
||||
{ "sm-client-state-file", 0, 0,
|
||||
G_OPTION_ARG_FILENAME, &sm_client_state_file,
|
||||
N_("Specify file containing saved configuration"), N_("FILE") },
|
||||
{ "sm-client-id", 0, 0,
|
||||
G_OPTION_ARG_STRING, &sm_client_id,
|
||||
N_("Specify session management ID"), N_("ID") },
|
||||
/* MateClient compatibility option */
|
||||
{ "sm-disable", 0, G_OPTION_FLAG_HIDDEN,
|
||||
G_OPTION_ARG_NONE, &sm_client_disable,
|
||||
NULL, NULL },
|
||||
/* MateClient compatibility option. This is a dummy option that only
|
||||
* exists so that sessions saved by apps with MateClient can be restored
|
||||
* later when they've switched to EggSMClient. See bug #575308.
|
||||
*/
|
||||
{ "sm-config-prefix", 0, G_OPTION_FLAG_HIDDEN,
|
||||
G_OPTION_ARG_STRING, &sm_config_prefix,
|
||||
NULL, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
GOptionGroup *group;
|
||||
|
||||
/* Use our own debug handler for the "EggSMClient" domain. */
|
||||
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
|
||||
egg_sm_client_debug_handler, NULL);
|
||||
|
||||
group = g_option_group_new ("sm-client",
|
||||
_("Session management options:"),
|
||||
_("Show session management options"),
|
||||
NULL, NULL);
|
||||
g_option_group_add_entries (group, entries);
|
||||
g_option_group_set_parse_hooks (group, NULL, sm_client_post_parse_func);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_sm_client_set_mode:
|
||||
* @mode: an #EggSMClient mode
|
||||
*
|
||||
* Sets the "mode" of #EggSMClient as follows:
|
||||
*
|
||||
* %EGG_SM_CLIENT_MODE_DISABLED: Session management is completely
|
||||
* disabled. The application will not even connect to the session
|
||||
* manager. (egg_sm_client_get() will still return an #EggSMClient,
|
||||
* but it will just be a dummy object.)
|
||||
*
|
||||
* %EGG_SM_CLIENT_MODE_NO_RESTART: The application will connect to
|
||||
* the session manager (and thus will receive notification when the
|
||||
* user is logging out, etc), but will request to not be
|
||||
* automatically restarted with saved state in future sessions.
|
||||
*
|
||||
* %EGG_SM_CLIENT_MODE_NORMAL: The default. #EggSMCLient will
|
||||
* function normally.
|
||||
*
|
||||
* This must be called before the application's main loop begins.
|
||||
**/
|
||||
void
|
||||
egg_sm_client_set_mode (EggSMClientMode mode)
|
||||
{
|
||||
global_client_mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_sm_client_get_mode:
|
||||
*
|
||||
* Gets the global #EggSMClientMode. See egg_sm_client_set_mode()
|
||||
* for details.
|
||||
*
|
||||
* Return value: the global #EggSMClientMode
|
||||
**/
|
||||
EggSMClientMode
|
||||
egg_sm_client_get_mode (void)
|
||||
{
|
||||
return global_client_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_sm_client_get:
|
||||
*
|
||||
* Returns the master #EggSMClient for the application.
|
||||
*
|
||||
* On platforms that support saved sessions (ie, POSIX/X11), the
|
||||
* application will only request to be restarted by the session
|
||||
* manager if you call egg_set_desktop_file() to set an application
|
||||
* desktop file. In particular, if the desktop file contains the key
|
||||
* "X
|
||||
*
|
||||
* Return value: the master #EggSMClient.
|
||||
**/
|
||||
EggSMClient *
|
||||
egg_sm_client_get (void)
|
||||
{
|
||||
if (!global_client)
|
||||
{
|
||||
if (global_client_mode != EGG_SM_CLIENT_MODE_DISABLED &&
|
||||
!sm_client_disable)
|
||||
{
|
||||
global_client = egg_sm_client_xsmp_new ();
|
||||
}
|
||||
|
||||
/* Fallback: create a dummy client, so that callers don't have
|
||||
* to worry about a %NULL return value.
|
||||
*/
|
||||
if (!global_client)
|
||||
global_client = g_object_new (EGG_TYPE_SM_CLIENT, NULL);
|
||||
}
|
||||
|
||||
return global_client;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_sm_client_is_resumed:
|
||||
* @client: the client
|
||||
*
|
||||
* Checks whether or not the current session has been resumed from
|
||||
* a previous saved session. If so, the application should call
|
||||
* egg_sm_client_get_state_file() and restore its state from the
|
||||
* returned #GKeyFile.
|
||||
*
|
||||
* Return value: %TRUE if the session has been resumed
|
||||
**/
|
||||
gboolean
|
||||
egg_sm_client_is_resumed (EggSMClient *client)
|
||||
{
|
||||
g_return_val_if_fail (client == global_client, FALSE);
|
||||
|
||||
return sm_client_state_file != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_sm_client_get_state_file:
|
||||
* @client: the client
|
||||
*
|
||||
* If the application was resumed by the session manager, this will
|
||||
* return the #GKeyFile containing its state from the previous
|
||||
* session.
|
||||
*
|
||||
* Note that other libraries and #EggSMClient itself may also store
|
||||
* state in the key file, so if you call egg_sm_client_get_groups(),
|
||||
* on it, the return value will likely include groups that you did not
|
||||
* put there yourself. (It is also not guaranteed that the first
|
||||
* group created by the application will still be the "start group"
|
||||
* when it is resumed.)
|
||||
*
|
||||
* Return value: the #GKeyFile containing the application's earlier
|
||||
* state, or %NULL on error. You should not free this key file; it
|
||||
* is owned by @client.
|
||||
**/
|
||||
GKeyFile *
|
||||
egg_sm_client_get_state_file (EggSMClient *client)
|
||||
{
|
||||
EggSMClientPrivate *priv = EGG_SM_CLIENT_GET_PRIVATE (client);
|
||||
char *state_file_path;
|
||||
GError *err = NULL;
|
||||
|
||||
g_return_val_if_fail (client == global_client, NULL);
|
||||
|
||||
if (!sm_client_state_file)
|
||||
return NULL;
|
||||
if (priv->state_file)
|
||||
return priv->state_file;
|
||||
|
||||
if (!strncmp (sm_client_state_file, "file://", 7))
|
||||
state_file_path = g_filename_from_uri (sm_client_state_file, NULL, NULL);
|
||||
else
|
||||
state_file_path = g_strdup (sm_client_state_file);
|
||||
|
||||
priv->state_file = g_key_file_new ();
|
||||
if (!g_key_file_load_from_file (priv->state_file, state_file_path, 0, &err))
|
||||
{
|
||||
g_warning ("Could not load SM state file '%s': %s",
|
||||
sm_client_state_file, err->message);
|
||||
g_clear_error (&err);
|
||||
g_key_file_free (priv->state_file);
|
||||
priv->state_file = NULL;
|
||||
}
|
||||
|
||||
g_free (state_file_path);
|
||||
return priv->state_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_sm_client_set_restart_command:
|
||||
* @client: the client
|
||||
* @argc: the length of @argv
|
||||
* @argv: argument vector
|
||||
*
|
||||
* Sets the command used to restart @client if it does not have a
|
||||
* .desktop file that can be used to find its restart command.
|
||||
*
|
||||
* This can also be used when handling the ::save_state signal, to
|
||||
* save the current state via an updated command line. (Eg, providing
|
||||
* a list of filenames to open when the application is resumed.)
|
||||
**/
|
||||
void
|
||||
egg_sm_client_set_restart_command (EggSMClient *client,
|
||||
int argc,
|
||||
const char **argv)
|
||||
{
|
||||
g_return_if_fail (EGG_IS_SM_CLIENT (client));
|
||||
|
||||
if (EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command)
|
||||
EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command (client, argc, argv);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_sm_client_will_quit:
|
||||
* @client: the client
|
||||
* @will_quit: whether or not the application is willing to quit
|
||||
*
|
||||
* This MUST be called in response to the ::quit_requested signal, to
|
||||
* indicate whether or not the application is willing to quit. The
|
||||
* application may call it either directly from the signal handler, or
|
||||
* at some later point (eg, after asynchronously interacting with the
|
||||
* user).
|
||||
*
|
||||
* If the application does not connect to ::quit_requested,
|
||||
* #EggSMClient will call this method on its behalf (passing %TRUE
|
||||
* for @will_quit).
|
||||
*
|
||||
* After calling this method, the application should wait to receive
|
||||
* either ::quit_cancelled or ::quit.
|
||||
**/
|
||||
void
|
||||
egg_sm_client_will_quit (EggSMClient *client,
|
||||
gboolean will_quit)
|
||||
{
|
||||
g_return_if_fail (EGG_IS_SM_CLIENT (client));
|
||||
|
||||
if (EGG_SM_CLIENT_GET_CLASS (client)->will_quit)
|
||||
EGG_SM_CLIENT_GET_CLASS (client)->will_quit (client, will_quit);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_sm_client_end_session:
|
||||
* @style: a hint at how to end the session
|
||||
* @request_confirmation: whether or not the user should get a chance
|
||||
* to confirm the action
|
||||
*
|
||||
* Requests that the session manager end the current session. @style
|
||||
* indicates how the session should be ended, and
|
||||
* @request_confirmation indicates whether or not the user should be
|
||||
* given a chance to confirm the logout/reboot/shutdown. Both of these
|
||||
* flags are merely hints though; the session manager may choose to
|
||||
* ignore them.
|
||||
*
|
||||
* Return value: %TRUE if the request was sent; %FALSE if it could not
|
||||
* be (eg, because it could not connect to the session manager).
|
||||
**/
|
||||
gboolean
|
||||
egg_sm_client_end_session (EggSMClientEndStyle style,
|
||||
gboolean request_confirmation)
|
||||
{
|
||||
EggSMClient *client = egg_sm_client_get ();
|
||||
|
||||
g_return_val_if_fail (EGG_IS_SM_CLIENT (client), FALSE);
|
||||
|
||||
if (EGG_SM_CLIENT_GET_CLASS (client)->end_session)
|
||||
{
|
||||
return EGG_SM_CLIENT_GET_CLASS (client)->end_session (client, style,
|
||||
request_confirmation);
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Signal-emitting callbacks from platform-specific code */
|
||||
|
||||
GKeyFile *
|
||||
egg_sm_client_save_state (EggSMClient *client)
|
||||
{
|
||||
GKeyFile *state_file;
|
||||
char *group;
|
||||
|
||||
g_return_val_if_fail (client == global_client, NULL);
|
||||
|
||||
state_file = g_key_file_new ();
|
||||
|
||||
g_debug ("Emitting save_state");
|
||||
g_signal_emit (client, signals[SAVE_STATE], 0, state_file);
|
||||
g_debug ("Done emitting save_state");
|
||||
|
||||
group = g_key_file_get_start_group (state_file);
|
||||
if (group)
|
||||
{
|
||||
g_free (group);
|
||||
return state_file;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_key_file_free (state_file);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
egg_sm_client_quit_requested (EggSMClient *client)
|
||||
{
|
||||
g_return_if_fail (client == global_client);
|
||||
|
||||
if (!g_signal_has_handler_pending (client, signals[QUIT_REQUESTED], 0, FALSE))
|
||||
{
|
||||
g_debug ("Not emitting quit_requested because no one is listening");
|
||||
egg_sm_client_will_quit (client, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
g_debug ("Emitting quit_requested");
|
||||
g_signal_emit (client, signals[QUIT_REQUESTED], 0);
|
||||
g_debug ("Done emitting quit_requested");
|
||||
}
|
||||
|
||||
void
|
||||
egg_sm_client_quit_cancelled (EggSMClient *client)
|
||||
{
|
||||
g_return_if_fail (client == global_client);
|
||||
|
||||
g_debug ("Emitting quit_cancelled");
|
||||
g_signal_emit (client, signals[QUIT_CANCELLED], 0);
|
||||
g_debug ("Done emitting quit_cancelled");
|
||||
}
|
||||
|
||||
void
|
||||
egg_sm_client_quit (EggSMClient *client)
|
||||
{
|
||||
g_return_if_fail (client == global_client);
|
||||
|
||||
g_debug ("Emitting quit");
|
||||
g_signal_emit (client, signals[QUIT], 0);
|
||||
g_debug ("Done emitting quit");
|
||||
|
||||
/* FIXME: should we just call gtk_main_quit() here? */
|
||||
}
|
||||
|
||||
static void
|
||||
egg_sm_client_debug_handler (const char *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const char *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
static int debug = -1;
|
||||
|
||||
if (debug < 0)
|
||||
debug = (g_getenv ("EGG_SM_CLIENT_DEBUG") != NULL);
|
||||
|
||||
if (debug)
|
||||
g_log_default_handler (log_domain, log_level, message, NULL);
|
||||
}
|
||||
117
xed/smclient/eggsmclient.h
Normal file
117
xed/smclient/eggsmclient.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/* eggsmclient.h
|
||||
* Copyright (C) 2007 Novell, Inc.
|
||||
*
|
||||
* 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 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __EGG_SM_CLIENT_H__
|
||||
#define __EGG_SM_CLIENT_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define EGG_TYPE_SM_CLIENT (egg_sm_client_get_type ())
|
||||
#define EGG_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT, EggSMClient))
|
||||
#define EGG_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT, EggSMClientClass))
|
||||
#define EGG_IS_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT))
|
||||
#define EGG_IS_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT))
|
||||
#define EGG_SM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT, EggSMClientClass))
|
||||
|
||||
typedef struct _EggSMClient EggSMClient;
|
||||
typedef struct _EggSMClientClass EggSMClientClass;
|
||||
typedef struct _EggSMClientPrivate EggSMClientPrivate;
|
||||
|
||||
typedef enum {
|
||||
EGG_SM_CLIENT_END_SESSION_DEFAULT,
|
||||
EGG_SM_CLIENT_LOGOUT,
|
||||
EGG_SM_CLIENT_REBOOT,
|
||||
EGG_SM_CLIENT_SHUTDOWN
|
||||
} EggSMClientEndStyle;
|
||||
|
||||
typedef enum {
|
||||
EGG_SM_CLIENT_MODE_DISABLED,
|
||||
EGG_SM_CLIENT_MODE_NO_RESTART,
|
||||
EGG_SM_CLIENT_MODE_NORMAL
|
||||
} EggSMClientMode;
|
||||
|
||||
struct _EggSMClient
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
};
|
||||
|
||||
struct _EggSMClientClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*save_state) (EggSMClient *client,
|
||||
GKeyFile *state_file);
|
||||
|
||||
void (*quit_requested) (EggSMClient *client);
|
||||
void (*quit_cancelled) (EggSMClient *client);
|
||||
void (*quit) (EggSMClient *client);
|
||||
|
||||
/* virtual methods */
|
||||
void (*startup) (EggSMClient *client,
|
||||
const char *client_id);
|
||||
void (*set_restart_command) (EggSMClient *client,
|
||||
int argc,
|
||||
const char **argv);
|
||||
void (*will_quit) (EggSMClient *client,
|
||||
gboolean will_quit);
|
||||
gboolean (*end_session) (EggSMClient *client,
|
||||
EggSMClientEndStyle style,
|
||||
gboolean request_confirmation);
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_egg_reserved1) (void);
|
||||
void (*_egg_reserved2) (void);
|
||||
void (*_egg_reserved3) (void);
|
||||
void (*_egg_reserved4) (void);
|
||||
};
|
||||
|
||||
GType egg_sm_client_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GOptionGroup *egg_sm_client_get_option_group (void);
|
||||
|
||||
/* Initialization */
|
||||
void egg_sm_client_set_mode (EggSMClientMode mode);
|
||||
EggSMClientMode egg_sm_client_get_mode (void);
|
||||
EggSMClient *egg_sm_client_get (void);
|
||||
|
||||
/* Resuming a saved session */
|
||||
gboolean egg_sm_client_is_resumed (EggSMClient *client);
|
||||
GKeyFile *egg_sm_client_get_state_file (EggSMClient *client);
|
||||
|
||||
/* Alternate means of saving state */
|
||||
void egg_sm_client_set_restart_command (EggSMClient *client,
|
||||
int argc,
|
||||
const char **argv);
|
||||
|
||||
/* Handling "quit_requested" signal */
|
||||
void egg_sm_client_will_quit (EggSMClient *client,
|
||||
gboolean will_quit);
|
||||
|
||||
/* Initiate a logout/reboot/shutdown */
|
||||
gboolean egg_sm_client_end_session (EggSMClientEndStyle style,
|
||||
gboolean request_confirmation);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
#endif /* __EGG_SM_CLIENT_H__ */
|
||||
824
xed/xed-app.c
Normal file
824
xed/xed-app.c
Normal file
@@ -0,0 +1,824 @@
|
||||
/*
|
||||
* xed-app.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005-2006 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "xed-app.h"
|
||||
#include "xed-prefs-manager-app.h"
|
||||
#include "xed-commands.h"
|
||||
#include "xed-notebook.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-utils.h"
|
||||
#include "xed-enum-types.h"
|
||||
#include "xed-dirs.h"
|
||||
|
||||
#define XED_PAGE_SETUP_FILE "xed-page-setup"
|
||||
#define XED_PRINT_SETTINGS_FILE "xed-print-settings"
|
||||
|
||||
#define XED_APP_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_APP, XedAppPrivate))
|
||||
|
||||
/* Properties */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
};
|
||||
|
||||
struct _XedAppPrivate
|
||||
{
|
||||
GList *windows;
|
||||
XedWindow *active_window;
|
||||
GtkPageSetup *page_setup;
|
||||
GtkPrintSettings *print_settings;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(XedApp, xed_app, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
xed_app_finalize (GObject *object)
|
||||
{
|
||||
XedApp *app = XED_APP (object);
|
||||
|
||||
g_list_free (app->priv->windows);
|
||||
|
||||
if (app->priv->page_setup)
|
||||
g_object_unref (app->priv->page_setup);
|
||||
if (app->priv->print_settings)
|
||||
g_object_unref (app->priv->print_settings);
|
||||
|
||||
G_OBJECT_CLASS (xed_app_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_app_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedApp *app = XED_APP (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_app_class_init (XedAppClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = xed_app_finalize;
|
||||
object_class->get_property = xed_app_get_property;
|
||||
|
||||
g_type_class_add_private (object_class, sizeof(XedAppPrivate));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ensure_user_config_dir (void)
|
||||
{
|
||||
gchar *config_dir;
|
||||
gboolean ret = TRUE;
|
||||
gint res;
|
||||
|
||||
config_dir = xed_dirs_get_user_config_dir ();
|
||||
if (config_dir == NULL)
|
||||
{
|
||||
g_warning ("Could not get config directory\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
res = g_mkdir_with_parents (config_dir, 0755);
|
||||
if (res < 0)
|
||||
{
|
||||
g_warning ("Could not create config directory\n");
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
g_free (config_dir);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
load_accels (void)
|
||||
{
|
||||
gchar *filename;
|
||||
|
||||
filename = xed_dirs_get_user_accels_file ();
|
||||
if (filename != NULL)
|
||||
{
|
||||
xed_debug_message (DEBUG_APP, "Loading keybindings from %s\n", filename);
|
||||
gtk_accel_map_load (filename);
|
||||
g_free (filename);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
save_accels (void)
|
||||
{
|
||||
gchar *filename;
|
||||
|
||||
filename = xed_dirs_get_user_accels_file ();
|
||||
if (filename != NULL)
|
||||
{
|
||||
xed_debug_message (DEBUG_APP, "Saving keybindings in %s\n", filename);
|
||||
gtk_accel_map_save (filename);
|
||||
g_free (filename);
|
||||
}
|
||||
}
|
||||
|
||||
static gchar *
|
||||
get_page_setup_file (void)
|
||||
{
|
||||
gchar *config_dir;
|
||||
gchar *setup = NULL;
|
||||
|
||||
config_dir = xed_dirs_get_user_config_dir ();
|
||||
|
||||
if (config_dir != NULL)
|
||||
{
|
||||
setup = g_build_filename (config_dir,
|
||||
XED_PAGE_SETUP_FILE,
|
||||
NULL);
|
||||
g_free (config_dir);
|
||||
}
|
||||
|
||||
return setup;
|
||||
}
|
||||
|
||||
static void
|
||||
load_page_setup (XedApp *app)
|
||||
{
|
||||
gchar *filename;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (app->priv->page_setup == NULL);
|
||||
|
||||
filename = get_page_setup_file ();
|
||||
|
||||
app->priv->page_setup = gtk_page_setup_new_from_file (filename,
|
||||
&error);
|
||||
if (error)
|
||||
{
|
||||
/* Ignore file not found error */
|
||||
if (error->domain != G_FILE_ERROR ||
|
||||
error->code != G_FILE_ERROR_NOENT)
|
||||
{
|
||||
g_warning ("%s", error->message);
|
||||
}
|
||||
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
|
||||
/* fall back to default settings */
|
||||
if (app->priv->page_setup == NULL)
|
||||
app->priv->page_setup = gtk_page_setup_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
save_page_setup (XedApp *app)
|
||||
{
|
||||
gchar *filename;
|
||||
GError *error = NULL;
|
||||
|
||||
if (app->priv->page_setup == NULL)
|
||||
return;
|
||||
|
||||
filename = get_page_setup_file ();
|
||||
|
||||
gtk_page_setup_to_file (app->priv->page_setup,
|
||||
filename,
|
||||
&error);
|
||||
if (error)
|
||||
{
|
||||
g_warning ("%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
get_print_settings_file (void)
|
||||
{
|
||||
gchar *config_dir;
|
||||
gchar *settings = NULL;
|
||||
|
||||
config_dir = xed_dirs_get_user_config_dir ();
|
||||
|
||||
if (config_dir != NULL)
|
||||
{
|
||||
settings = g_build_filename (config_dir,
|
||||
XED_PRINT_SETTINGS_FILE,
|
||||
NULL);
|
||||
g_free (config_dir);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
static void
|
||||
load_print_settings (XedApp *app)
|
||||
{
|
||||
gchar *filename;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (app->priv->print_settings == NULL);
|
||||
|
||||
filename = get_print_settings_file ();
|
||||
|
||||
app->priv->print_settings = gtk_print_settings_new_from_file (filename,
|
||||
&error);
|
||||
if (error)
|
||||
{
|
||||
/* Ignore file not found error */
|
||||
if (error->domain != G_FILE_ERROR ||
|
||||
error->code != G_FILE_ERROR_NOENT)
|
||||
{
|
||||
g_warning ("%s", error->message);
|
||||
}
|
||||
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
|
||||
/* fall back to default settings */
|
||||
if (app->priv->print_settings == NULL)
|
||||
app->priv->print_settings = gtk_print_settings_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
save_print_settings (XedApp *app)
|
||||
{
|
||||
gchar *filename;
|
||||
GError *error = NULL;
|
||||
|
||||
if (app->priv->print_settings == NULL)
|
||||
return;
|
||||
|
||||
filename = get_print_settings_file ();
|
||||
|
||||
gtk_print_settings_to_file (app->priv->print_settings,
|
||||
filename,
|
||||
&error);
|
||||
if (error)
|
||||
{
|
||||
g_warning ("%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_app_init (XedApp *app)
|
||||
{
|
||||
app->priv = XED_APP_GET_PRIVATE (app);
|
||||
|
||||
load_accels ();
|
||||
}
|
||||
|
||||
static void
|
||||
app_weak_notify (gpointer data,
|
||||
GObject *where_the_app_was)
|
||||
{
|
||||
gtk_main_quit ();
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_app_get_default:
|
||||
*
|
||||
* Returns the #XedApp object. This object is a singleton and
|
||||
* represents the running xed instance.
|
||||
*
|
||||
* Return value: the #XedApp pointer
|
||||
*/
|
||||
XedApp *
|
||||
xed_app_get_default (void)
|
||||
{
|
||||
static XedApp *app = NULL;
|
||||
|
||||
if (app != NULL)
|
||||
return app;
|
||||
|
||||
app = XED_APP (g_object_new (XED_TYPE_APP, NULL));
|
||||
|
||||
g_object_add_weak_pointer (G_OBJECT (app),
|
||||
(gpointer) &app);
|
||||
g_object_weak_ref (G_OBJECT (app),
|
||||
app_weak_notify,
|
||||
NULL);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void
|
||||
set_active_window (XedApp *app,
|
||||
XedWindow *window)
|
||||
{
|
||||
app->priv->active_window = window;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
window_focus_in_event (XedWindow *window,
|
||||
GdkEventFocus *event,
|
||||
XedApp *app)
|
||||
{
|
||||
/* updates active_view and active_child when a new toplevel receives focus */
|
||||
g_return_val_if_fail (XED_IS_WINDOW (window), FALSE);
|
||||
|
||||
set_active_window (app, window);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
window_delete_event (XedWindow *window,
|
||||
GdkEvent *event,
|
||||
XedApp *app)
|
||||
{
|
||||
XedWindowState ws;
|
||||
|
||||
ws = xed_window_get_state (window);
|
||||
|
||||
if (ws &
|
||||
(XED_WINDOW_STATE_SAVING |
|
||||
XED_WINDOW_STATE_PRINTING |
|
||||
XED_WINDOW_STATE_SAVING_SESSION))
|
||||
return TRUE;
|
||||
|
||||
_xed_cmd_file_quit (NULL, window);
|
||||
|
||||
/* Do not destroy the window */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
window_destroy (XedWindow *window,
|
||||
XedApp *app)
|
||||
{
|
||||
app->priv->windows = g_list_remove (app->priv->windows,
|
||||
window);
|
||||
|
||||
if (window == app->priv->active_window)
|
||||
{
|
||||
set_active_window (app, app->priv->windows != NULL ? app->priv->windows->data : NULL);
|
||||
}
|
||||
|
||||
/* CHECK: I don't think we have to disconnect this function, since windows
|
||||
is being destroyed */
|
||||
/*
|
||||
g_signal_handlers_disconnect_by_func (window,
|
||||
G_CALLBACK (window_focus_in_event),
|
||||
app);
|
||||
g_signal_handlers_disconnect_by_func (window,
|
||||
G_CALLBACK (window_destroy),
|
||||
app);
|
||||
*/
|
||||
if (app->priv->windows == NULL)
|
||||
{
|
||||
/* Last window is gone... save some settings and exit */
|
||||
ensure_user_config_dir ();
|
||||
|
||||
save_accels ();
|
||||
save_page_setup (app);
|
||||
save_print_settings (app);
|
||||
|
||||
g_object_unref (app);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generates a unique string for a window role */
|
||||
static gchar *
|
||||
gen_role (void)
|
||||
{
|
||||
GTimeVal result;
|
||||
static gint serial;
|
||||
|
||||
g_get_current_time (&result);
|
||||
|
||||
return g_strdup_printf ("xed-window-%ld-%ld-%d-%s",
|
||||
result.tv_sec,
|
||||
result.tv_usec,
|
||||
serial++,
|
||||
g_get_host_name ());
|
||||
}
|
||||
|
||||
static XedWindow *
|
||||
xed_app_create_window_real (XedApp *app,
|
||||
gboolean set_geometry,
|
||||
const gchar *role)
|
||||
{
|
||||
XedWindow *window;
|
||||
|
||||
xed_debug (DEBUG_APP);
|
||||
|
||||
/*
|
||||
* We need to be careful here, there is a race condition:
|
||||
* when another xed is launched it checks active_window,
|
||||
* so we must do our best to ensure that active_window
|
||||
* is never NULL when at least a window exists.
|
||||
*/
|
||||
if (app->priv->windows == NULL)
|
||||
{
|
||||
window = g_object_new (XED_TYPE_WINDOW, NULL);
|
||||
set_active_window (app, window);
|
||||
}
|
||||
else
|
||||
{
|
||||
window = g_object_new (XED_TYPE_WINDOW, NULL);
|
||||
}
|
||||
|
||||
app->priv->windows = g_list_prepend (app->priv->windows,
|
||||
window);
|
||||
|
||||
xed_debug_message (DEBUG_APP, "Window created");
|
||||
|
||||
if (role != NULL)
|
||||
{
|
||||
gtk_window_set_role (GTK_WINDOW (window), role);
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar *newrole;
|
||||
|
||||
newrole = gen_role ();
|
||||
gtk_window_set_role (GTK_WINDOW (window), newrole);
|
||||
g_free (newrole);
|
||||
}
|
||||
|
||||
if (set_geometry)
|
||||
{
|
||||
GdkWindowState state;
|
||||
gint w, h;
|
||||
|
||||
state = xed_prefs_manager_get_window_state ();
|
||||
|
||||
if ((state & GDK_WINDOW_STATE_MAXIMIZED) != 0)
|
||||
{
|
||||
xed_prefs_manager_get_default_window_size (&w, &h);
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), w, h);
|
||||
gtk_window_maximize (GTK_WINDOW (window));
|
||||
}
|
||||
else
|
||||
{
|
||||
xed_prefs_manager_get_window_size (&w, &h);
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), w, h);
|
||||
gtk_window_unmaximize (GTK_WINDOW (window));
|
||||
}
|
||||
|
||||
if ((state & GDK_WINDOW_STATE_STICKY ) != 0)
|
||||
gtk_window_stick (GTK_WINDOW (window));
|
||||
else
|
||||
gtk_window_unstick (GTK_WINDOW (window));
|
||||
}
|
||||
|
||||
g_signal_connect (window,
|
||||
"focus_in_event",
|
||||
G_CALLBACK (window_focus_in_event),
|
||||
app);
|
||||
g_signal_connect (window,
|
||||
"delete_event",
|
||||
G_CALLBACK (window_delete_event),
|
||||
app);
|
||||
g_signal_connect (window,
|
||||
"destroy",
|
||||
G_CALLBACK (window_destroy),
|
||||
app);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_app_create_window:
|
||||
* @app: the #XedApp
|
||||
* @screen: (allow-none):
|
||||
*
|
||||
* Create a new #XedWindow part of @app.
|
||||
*
|
||||
* Return value: the new #XedWindow
|
||||
*/
|
||||
XedWindow *
|
||||
xed_app_create_window (XedApp *app,
|
||||
GdkScreen *screen)
|
||||
{
|
||||
XedWindow *window;
|
||||
|
||||
window = xed_app_create_window_real (app, TRUE, NULL);
|
||||
|
||||
if (screen != NULL)
|
||||
gtk_window_set_screen (GTK_WINDOW (window), screen);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as _create_window, but doesn't set the geometry.
|
||||
* The session manager takes care of it. Used in mate-session.
|
||||
*/
|
||||
XedWindow *
|
||||
_xed_app_restore_window (XedApp *app,
|
||||
const gchar *role)
|
||||
{
|
||||
XedWindow *window;
|
||||
|
||||
window = xed_app_create_window_real (app, FALSE, role);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_app_get_windows:
|
||||
* @app: the #XedApp
|
||||
*
|
||||
* Returns all the windows currently present in #XedApp.
|
||||
*
|
||||
* Return value: (transfer none): the list of #XedWindows objects.
|
||||
* The list should not be freed
|
||||
*/
|
||||
const GList *
|
||||
xed_app_get_windows (XedApp *app)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_APP (app), NULL);
|
||||
|
||||
return app->priv->windows;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_app_get_active_window:
|
||||
* @app: the #XedApp
|
||||
*
|
||||
* Retrives the #XedWindow currently active.
|
||||
*
|
||||
* Return value: the active #XedWindow
|
||||
*/
|
||||
XedWindow *
|
||||
xed_app_get_active_window (XedApp *app)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_APP (app), NULL);
|
||||
|
||||
/* make sure our active window is always realized:
|
||||
* this is needed on startup if we launch two xed fast
|
||||
* enough that the second instance comes up before the
|
||||
* first one shows its window.
|
||||
*/
|
||||
if (!gtk_widget_get_realized (GTK_WIDGET (app->priv->active_window)))
|
||||
gtk_widget_realize (GTK_WIDGET (app->priv->active_window));
|
||||
|
||||
return app->priv->active_window;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_in_viewport (XedWindow *window,
|
||||
GdkScreen *screen,
|
||||
gint workspace,
|
||||
gint viewport_x,
|
||||
gint viewport_y)
|
||||
{
|
||||
GdkScreen *s;
|
||||
GdkDisplay *display;
|
||||
GdkWindow *gdkwindow;
|
||||
const gchar *cur_name;
|
||||
const gchar *name;
|
||||
gint cur_n;
|
||||
gint n;
|
||||
gint ws;
|
||||
gint sc_width, sc_height;
|
||||
gint x, y, width, height;
|
||||
gint vp_x, vp_y;
|
||||
|
||||
/* Check for screen and display match */
|
||||
display = gdk_screen_get_display (screen);
|
||||
cur_name = gdk_display_get_name (display);
|
||||
cur_n = gdk_screen_get_number (screen);
|
||||
|
||||
s = gtk_window_get_screen (GTK_WINDOW (window));
|
||||
display = gdk_screen_get_display (s);
|
||||
name = gdk_display_get_name (display);
|
||||
n = gdk_screen_get_number (s);
|
||||
|
||||
if (strcmp (cur_name, name) != 0 || cur_n != n)
|
||||
return FALSE;
|
||||
|
||||
/* Check for workspace match */
|
||||
ws = xed_utils_get_window_workspace (GTK_WINDOW (window));
|
||||
if (ws != workspace && ws != XED_ALL_WORKSPACES)
|
||||
return FALSE;
|
||||
|
||||
/* Check for viewport match */
|
||||
gdkwindow = gtk_widget_get_window (GTK_WIDGET (window));
|
||||
gdk_window_get_position (gdkwindow, &x, &y);
|
||||
|
||||
width = gdk_window_get_width(gdkwindow);
|
||||
height = gdk_window_get_height(gdkwindow);
|
||||
|
||||
xed_utils_get_current_viewport (screen, &vp_x, &vp_y);
|
||||
x += vp_x;
|
||||
y += vp_y;
|
||||
|
||||
sc_width = gdk_screen_get_width (screen);
|
||||
sc_height = gdk_screen_get_height (screen);
|
||||
|
||||
return x + width * .25 >= viewport_x &&
|
||||
x + width * .75 <= viewport_x + sc_width &&
|
||||
y >= viewport_y &&
|
||||
y + height <= viewport_y + sc_height;
|
||||
}
|
||||
|
||||
/**
|
||||
* _xed_app_get_window_in_viewport
|
||||
* @app: the #XedApp
|
||||
* @screen: the #GdkScreen
|
||||
* @workspace: the workspace number
|
||||
* @viewport_x: the viewport horizontal origin
|
||||
* @viewport_y: the viewport vertical origin
|
||||
*
|
||||
* Since a workspace can be larger than the screen, it is divided into several
|
||||
* equal parts called viewports. This function retrives the #XedWindow in
|
||||
* the given viewport of the given workspace.
|
||||
*
|
||||
* Return value: the #XedWindow in the given viewport of the given workspace.
|
||||
*/
|
||||
XedWindow *
|
||||
_xed_app_get_window_in_viewport (XedApp *app,
|
||||
GdkScreen *screen,
|
||||
gint workspace,
|
||||
gint viewport_x,
|
||||
gint viewport_y)
|
||||
{
|
||||
XedWindow *window;
|
||||
|
||||
GList *l;
|
||||
|
||||
g_return_val_if_fail (XED_IS_APP (app), NULL);
|
||||
|
||||
/* first try if the active window */
|
||||
window = app->priv->active_window;
|
||||
|
||||
g_return_val_if_fail (XED_IS_WINDOW (window), NULL);
|
||||
|
||||
if (is_in_viewport (window, screen, workspace, viewport_x, viewport_y))
|
||||
return window;
|
||||
|
||||
/* otherwise try to see if there is a window on this workspace */
|
||||
for (l = app->priv->windows; l != NULL; l = l->next)
|
||||
{
|
||||
window = l->data;
|
||||
|
||||
if (is_in_viewport (window, screen, workspace, viewport_x, viewport_y))
|
||||
return window;
|
||||
}
|
||||
|
||||
/* no window on this workspace... create a new one */
|
||||
return xed_app_create_window (app, screen);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_app_get_documents:
|
||||
* @app: the #XedApp
|
||||
*
|
||||
* Returns all the documents currently open in #XedApp.
|
||||
*
|
||||
* Return value: (element-type Xed.Document) (transfer container):
|
||||
* a newly allocated list of #XedDocument objects
|
||||
*/
|
||||
GList *
|
||||
xed_app_get_documents (XedApp *app)
|
||||
{
|
||||
GList *res = NULL;
|
||||
GList *windows;
|
||||
|
||||
g_return_val_if_fail (XED_IS_APP (app), NULL);
|
||||
|
||||
windows = app->priv->windows;
|
||||
|
||||
while (windows != NULL)
|
||||
{
|
||||
res = g_list_concat (res,
|
||||
xed_window_get_documents (XED_WINDOW (windows->data)));
|
||||
|
||||
windows = g_list_next (windows);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_app_get_views:
|
||||
* @app: the #XedApp
|
||||
*
|
||||
* Returns all the views currently present in #XedApp.
|
||||
*
|
||||
* Return value: (element-type Xed.View) (transfer container):
|
||||
* a newly allocated list of #XedView objects
|
||||
*/
|
||||
GList *
|
||||
xed_app_get_views (XedApp *app)
|
||||
{
|
||||
GList *res = NULL;
|
||||
GList *windows;
|
||||
|
||||
g_return_val_if_fail (XED_IS_APP (app), NULL);
|
||||
|
||||
windows = app->priv->windows;
|
||||
|
||||
while (windows != NULL)
|
||||
{
|
||||
res = g_list_concat (res,
|
||||
xed_window_get_views (XED_WINDOW (windows->data)));
|
||||
|
||||
windows = g_list_next (windows);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Returns a copy */
|
||||
GtkPageSetup *
|
||||
_xed_app_get_default_page_setup (XedApp *app)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_APP (app), NULL);
|
||||
|
||||
if (app->priv->page_setup == NULL)
|
||||
load_page_setup (app);
|
||||
|
||||
return gtk_page_setup_copy (app->priv->page_setup);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_app_set_default_page_setup (XedApp *app,
|
||||
GtkPageSetup *page_setup)
|
||||
{
|
||||
g_return_if_fail (XED_IS_APP (app));
|
||||
g_return_if_fail (GTK_IS_PAGE_SETUP (page_setup));
|
||||
|
||||
if (app->priv->page_setup != NULL)
|
||||
g_object_unref (app->priv->page_setup);
|
||||
|
||||
app->priv->page_setup = g_object_ref (page_setup);
|
||||
}
|
||||
|
||||
/* Returns a copy */
|
||||
GtkPrintSettings *
|
||||
_xed_app_get_default_print_settings (XedApp *app)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_APP (app), NULL);
|
||||
|
||||
if (app->priv->print_settings == NULL)
|
||||
load_print_settings (app);
|
||||
|
||||
return gtk_print_settings_copy (app->priv->print_settings);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_app_set_default_print_settings (XedApp *app,
|
||||
GtkPrintSettings *settings)
|
||||
{
|
||||
g_return_if_fail (XED_IS_APP (app));
|
||||
g_return_if_fail (GTK_IS_PRINT_SETTINGS (settings));
|
||||
|
||||
if (app->priv->print_settings != NULL)
|
||||
g_object_unref (app->priv->print_settings);
|
||||
|
||||
app->priv->print_settings = g_object_ref (settings);
|
||||
}
|
||||
|
||||
116
xed/xed-app.h
Normal file
116
xed/xed-app.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* xed-app.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_APP_H__
|
||||
#define __XED_APP_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <xed/xed-window.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_APP (xed_app_get_type())
|
||||
#define XED_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_APP, XedApp))
|
||||
#define XED_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_APP, XedAppClass))
|
||||
#define XED_IS_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_APP))
|
||||
#define XED_IS_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_APP))
|
||||
#define XED_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_APP, XedAppClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedAppPrivate XedAppPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedApp XedApp;
|
||||
|
||||
struct _XedApp
|
||||
{
|
||||
GObject object;
|
||||
|
||||
/*< private > */
|
||||
XedAppPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedAppClass XedAppClass;
|
||||
|
||||
struct _XedAppClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_app_get_type (void) G_GNUC_CONST;
|
||||
|
||||
XedApp *xed_app_get_default (void);
|
||||
|
||||
XedWindow *xed_app_create_window (XedApp *app,
|
||||
GdkScreen *screen);
|
||||
|
||||
const GList *xed_app_get_windows (XedApp *app);
|
||||
XedWindow *xed_app_get_active_window (XedApp *app);
|
||||
|
||||
/* Returns a newly allocated list with all the documents */
|
||||
GList *xed_app_get_documents (XedApp *app);
|
||||
|
||||
/* Returns a newly allocated list with all the views */
|
||||
GList *xed_app_get_views (XedApp *app);
|
||||
|
||||
/*
|
||||
* Non exported functions
|
||||
*/
|
||||
XedWindow *_xed_app_restore_window (XedApp *app,
|
||||
const gchar *role);
|
||||
XedWindow *_xed_app_get_window_in_viewport (XedApp *app,
|
||||
GdkScreen *screen,
|
||||
gint workspace,
|
||||
gint viewport_x,
|
||||
gint viewport_y);
|
||||
|
||||
/* global print config */
|
||||
GtkPageSetup *_xed_app_get_default_page_setup (XedApp *app);
|
||||
void _xed_app_set_default_page_setup (XedApp *app,
|
||||
GtkPageSetup *page_setup);
|
||||
GtkPrintSettings *_xed_app_get_default_print_settings (XedApp *app);
|
||||
void _xed_app_set_default_print_settings (XedApp *app,
|
||||
GtkPrintSettings *settings);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_APP_H__ */
|
||||
84
xed/xed-close-button.c
Normal file
84
xed/xed-close-button.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* xed-close-button.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2010 - Paolo Borelli
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "xed-close-button.h"
|
||||
|
||||
G_DEFINE_TYPE (XedCloseButton, xed_close_button, GTK_TYPE_BUTTON)
|
||||
|
||||
static void
|
||||
xed_close_button_style_set (GtkWidget *button,
|
||||
GtkStyle *previous_style)
|
||||
{
|
||||
gint h, w;
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 10, 0)
|
||||
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
|
||||
#else
|
||||
gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button),
|
||||
GTK_ICON_SIZE_MENU, &w, &h);
|
||||
#endif
|
||||
|
||||
gtk_widget_set_size_request (button, w + 2, h + 2);
|
||||
|
||||
GTK_WIDGET_CLASS (xed_close_button_parent_class)->style_set (button, previous_style);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_close_button_class_init (XedCloseButtonClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
widget_class->style_set = xed_close_button_style_set;
|
||||
}
|
||||
|
||||
static void
|
||||
xed_close_button_init (XedCloseButton *button)
|
||||
{
|
||||
GtkRcStyle *rcstyle;
|
||||
GtkWidget *image;
|
||||
|
||||
/* make it as small as possible */
|
||||
rcstyle = gtk_rc_style_new ();
|
||||
rcstyle->xthickness = rcstyle->ythickness = 0;
|
||||
gtk_widget_modify_style (GTK_WIDGET (button), rcstyle);
|
||||
g_object_unref (rcstyle);
|
||||
|
||||
image = gtk_image_new_from_stock (GTK_STOCK_CLOSE,
|
||||
GTK_ICON_SIZE_MENU);
|
||||
gtk_widget_show (image);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (button), image);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
xed_close_button_new ()
|
||||
{
|
||||
XedCloseButton *button;
|
||||
|
||||
button = g_object_new (XED_TYPE_CLOSE_BUTTON,
|
||||
"relief", GTK_RELIEF_NONE,
|
||||
"focus-on-click", FALSE,
|
||||
NULL);
|
||||
|
||||
return GTK_WIDGET (button);
|
||||
}
|
||||
|
||||
56
xed/xed-close-button.h
Normal file
56
xed/xed-close-button.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* xed-close-button.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2010 - Paolo Borelli
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __XED_CLOSE_BUTTON_H__
|
||||
#define __XED_CLOSE_BUTTON_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_CLOSE_BUTTON (xed_close_button_get_type ())
|
||||
#define XED_CLOSE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_CLOSE_BUTTON, XedCloseButton))
|
||||
#define XED_CLOSE_BUTTON_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_CLOSE_BUTTON, XedCloseButton const))
|
||||
#define XED_CLOSE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_CLOSE_BUTTON, XedCloseButtonClass))
|
||||
#define XED_IS_CLOSE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_CLOSE_BUTTON))
|
||||
#define XED_IS_CLOSE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_CLOSE_BUTTON))
|
||||
#define XED_CLOSE_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_CLOSE_BUTTON, XedCloseButtonClass))
|
||||
|
||||
typedef struct _XedCloseButton XedCloseButton;
|
||||
typedef struct _XedCloseButtonClass XedCloseButtonClass;
|
||||
typedef struct _XedCloseButtonPrivate XedCloseButtonPrivate;
|
||||
|
||||
struct _XedCloseButton {
|
||||
GtkButton parent;
|
||||
};
|
||||
|
||||
struct _XedCloseButtonClass {
|
||||
GtkButtonClass parent_class;
|
||||
};
|
||||
|
||||
GType xed_close_button_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget *xed_close_button_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_CLOSE_BUTTON_H__ */
|
||||
87
xed/xed-commands-documents.c
Normal file
87
xed/xed-commands-documents.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* xed-documents-commands.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
|
||||
* Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 1998-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "xed-commands.h"
|
||||
#include "xed-window.h"
|
||||
#include "xed-notebook.h"
|
||||
#include "xed-debug.h"
|
||||
|
||||
void
|
||||
_xed_cmd_documents_previous_document (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
GtkNotebook *notebook;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
notebook = GTK_NOTEBOOK (_xed_window_get_notebook (window));
|
||||
gtk_notebook_prev_page (notebook);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_documents_next_document (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
GtkNotebook *notebook;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
notebook = GTK_NOTEBOOK (_xed_window_get_notebook (window));
|
||||
gtk_notebook_next_page (notebook);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_documents_move_to_new_window (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedNotebook *old_notebook;
|
||||
XedTab *tab;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
tab = xed_window_get_active_tab (window);
|
||||
|
||||
if (tab == NULL)
|
||||
return;
|
||||
|
||||
old_notebook = XED_NOTEBOOK (_xed_window_get_notebook (window));
|
||||
|
||||
g_return_if_fail (gtk_notebook_get_n_pages (GTK_NOTEBOOK (old_notebook)) > 1);
|
||||
|
||||
_xed_window_move_tab_to_new_window (window, tab);
|
||||
}
|
||||
174
xed/xed-commands-edit.c
Normal file
174
xed/xed-commands-edit.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* xed-commands-edit.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
|
||||
* Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 1998-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "xed-commands.h"
|
||||
#include "xed-window.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-view.h"
|
||||
#include "dialogs/xed-preferences-dialog.h"
|
||||
|
||||
void
|
||||
_xed_cmd_edit_undo (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedView *active_view;
|
||||
GtkSourceBuffer *active_document;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
active_view = xed_window_get_active_view (window);
|
||||
g_return_if_fail (active_view);
|
||||
|
||||
active_document = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (active_view)));
|
||||
|
||||
gtk_source_buffer_undo (active_document);
|
||||
|
||||
xed_view_scroll_to_cursor (active_view);
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_edit_redo (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedView *active_view;
|
||||
GtkSourceBuffer *active_document;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
active_view = xed_window_get_active_view (window);
|
||||
g_return_if_fail (active_view);
|
||||
|
||||
active_document = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (active_view)));
|
||||
|
||||
gtk_source_buffer_redo (active_document);
|
||||
|
||||
xed_view_scroll_to_cursor (active_view);
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_edit_cut (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedView *active_view;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
active_view = xed_window_get_active_view (window);
|
||||
g_return_if_fail (active_view);
|
||||
|
||||
xed_view_cut_clipboard (active_view);
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_edit_copy (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedView *active_view;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
active_view = xed_window_get_active_view (window);
|
||||
g_return_if_fail (active_view);
|
||||
|
||||
xed_view_copy_clipboard (active_view);
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_edit_paste (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedView *active_view;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
active_view = xed_window_get_active_view (window);
|
||||
g_return_if_fail (active_view);
|
||||
|
||||
xed_view_paste_clipboard (active_view);
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_edit_delete (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedView *active_view;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
active_view = xed_window_get_active_view (window);
|
||||
g_return_if_fail (active_view);
|
||||
|
||||
xed_view_delete_selection (active_view);
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_edit_select_all (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedView *active_view;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
active_view = xed_window_get_active_view (window);
|
||||
g_return_if_fail (active_view);
|
||||
|
||||
xed_view_select_all (active_view);
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_edit_preferences (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
xed_show_preferences_dialog (window);
|
||||
}
|
||||
74
xed/xed-commands-file-print.c
Normal file
74
xed/xed-commands-file-print.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* xed-commands-file-print.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
|
||||
* Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 1998-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "xed-commands.h"
|
||||
#include "xed-window.h"
|
||||
#include "xed-tab.h"
|
||||
#include "xed-debug.h"
|
||||
|
||||
void
|
||||
_xed_cmd_file_print_preview (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedTab *tab;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
tab = xed_window_get_active_tab (window);
|
||||
if (tab == NULL)
|
||||
return;
|
||||
|
||||
_xed_tab_print_preview (tab);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_file_print (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedTab *tab;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
tab = xed_window_get_active_tab (window);
|
||||
if (tab == NULL)
|
||||
return;
|
||||
|
||||
_xed_tab_print (tab);
|
||||
}
|
||||
|
||||
1847
xed/xed-commands-file.c
Normal file
1847
xed/xed-commands-file.c
Normal file
File diff suppressed because it is too large
Load Diff
67
xed/xed-commands-help.c
Normal file
67
xed/xed-commands-help.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* xed-help-commands.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
|
||||
* Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
* Copyright (C) 2011 Perberos
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the gedit Team, 1998-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "xed-commands.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-help.h"
|
||||
#include "xed-dirs.h"
|
||||
|
||||
void _xed_cmd_help_contents(GtkAction* action, XedWindow* window)
|
||||
{
|
||||
xed_debug(DEBUG_COMMANDS);
|
||||
|
||||
xed_help_display(GTK_WINDOW(window), NULL, NULL);
|
||||
}
|
||||
|
||||
void _xed_cmd_help_about(GtkAction* action, XedWindow* window)
|
||||
{
|
||||
static const gchar comments[] = \
|
||||
N_("A small and lightweight text editor");
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
gtk_show_about_dialog(GTK_WINDOW(window),
|
||||
"program-name", "xed",
|
||||
"comments", _(comments),
|
||||
"logo_icon_name", "accessories-text-editor",
|
||||
"version", VERSION,
|
||||
"website", "http://github.com/linuxmint/xed",
|
||||
NULL);
|
||||
}
|
||||
793
xed/xed-commands-search.c
Normal file
793
xed/xed-commands-search.c
Normal file
@@ -0,0 +1,793 @@
|
||||
/*
|
||||
* xed-search-commands.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
|
||||
* Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
|
||||
* Copyright (C) 2002-2006 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 1998-2006. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
#define GTK_OBJECT G_OBJECT
|
||||
#endif
|
||||
|
||||
#include "xed-commands.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-statusbar.h"
|
||||
#include "xed-window.h"
|
||||
#include "xed-window-private.h"
|
||||
#include "xed-utils.h"
|
||||
#include "dialogs/xed-search-dialog.h"
|
||||
|
||||
#define XED_SEARCH_DIALOG_KEY "xed-search-dialog-key"
|
||||
#define XED_LAST_SEARCH_DATA_KEY "xed-last-search-data-key"
|
||||
|
||||
typedef struct _LastSearchData LastSearchData;
|
||||
struct _LastSearchData
|
||||
{
|
||||
gint x;
|
||||
gint y;
|
||||
};
|
||||
|
||||
static void
|
||||
last_search_data_free (LastSearchData *data)
|
||||
{
|
||||
g_slice_free (LastSearchData, data);
|
||||
}
|
||||
|
||||
static void
|
||||
last_search_data_restore_position (XedSearchDialog *dlg)
|
||||
{
|
||||
LastSearchData *data;
|
||||
|
||||
data = g_object_get_data (G_OBJECT (dlg), XED_LAST_SEARCH_DATA_KEY);
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
gtk_window_move (GTK_WINDOW (dlg),
|
||||
data->x,
|
||||
data->y);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
last_search_data_store_position (XedSearchDialog *dlg)
|
||||
{
|
||||
LastSearchData *data;
|
||||
|
||||
data = g_object_get_data (G_OBJECT (dlg), XED_LAST_SEARCH_DATA_KEY);
|
||||
|
||||
if (data == NULL)
|
||||
{
|
||||
data = g_slice_new (LastSearchData);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (dlg),
|
||||
XED_LAST_SEARCH_DATA_KEY,
|
||||
data,
|
||||
(GDestroyNotify) last_search_data_free);
|
||||
}
|
||||
|
||||
gtk_window_get_position (GTK_WINDOW (dlg),
|
||||
&data->x,
|
||||
&data->y);
|
||||
}
|
||||
|
||||
/* Use occurrences only for Replace All */
|
||||
static void
|
||||
text_found (XedWindow *window,
|
||||
gint occurrences)
|
||||
{
|
||||
if (occurrences > 1)
|
||||
{
|
||||
xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
|
||||
window->priv->generic_message_cid,
|
||||
ngettext("Found and replaced %d occurrence",
|
||||
"Found and replaced %d occurrences",
|
||||
occurrences),
|
||||
occurrences);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (occurrences == 1)
|
||||
xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
|
||||
window->priv->generic_message_cid,
|
||||
_("Found and replaced one occurrence"));
|
||||
else
|
||||
xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
|
||||
window->priv->generic_message_cid,
|
||||
" ");
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_MSG_LENGTH 40
|
||||
static void
|
||||
text_not_found (XedWindow *window,
|
||||
const gchar *text)
|
||||
{
|
||||
gchar *searched;
|
||||
|
||||
searched = xed_utils_str_end_truncate (text, MAX_MSG_LENGTH);
|
||||
|
||||
xed_statusbar_flash_message (XED_STATUSBAR (window->priv->statusbar),
|
||||
window->priv->generic_message_cid,
|
||||
/* Translators: %s is replaced by the text
|
||||
entered by the user in the search box */
|
||||
_("\"%s\" not found"), searched);
|
||||
g_free (searched);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
run_search (XedView *view,
|
||||
gboolean wrap_around,
|
||||
gboolean search_backwards)
|
||||
{
|
||||
XedDocument *doc;
|
||||
GtkTextIter start_iter;
|
||||
GtkTextIter match_start;
|
||||
GtkTextIter match_end;
|
||||
gboolean found = FALSE;
|
||||
|
||||
doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
|
||||
|
||||
if (!search_backwards)
|
||||
{
|
||||
gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
|
||||
NULL,
|
||||
&start_iter);
|
||||
|
||||
found = xed_document_search_forward (doc,
|
||||
&start_iter,
|
||||
NULL,
|
||||
&match_start,
|
||||
&match_end);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
|
||||
&start_iter,
|
||||
NULL);
|
||||
|
||||
found = xed_document_search_backward (doc,
|
||||
NULL,
|
||||
&start_iter,
|
||||
&match_start,
|
||||
&match_end);
|
||||
}
|
||||
|
||||
if (!found && wrap_around)
|
||||
{
|
||||
if (!search_backwards)
|
||||
found = xed_document_search_forward (doc,
|
||||
NULL,
|
||||
NULL, /* FIXME: set the end_inter */
|
||||
&match_start,
|
||||
&match_end);
|
||||
else
|
||||
found = xed_document_search_backward (doc,
|
||||
NULL, /* FIXME: set the start_inter */
|
||||
NULL,
|
||||
&match_start,
|
||||
&match_end);
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
|
||||
&match_start);
|
||||
|
||||
gtk_text_buffer_move_mark_by_name (GTK_TEXT_BUFFER (doc),
|
||||
"selection_bound",
|
||||
&match_end);
|
||||
|
||||
xed_view_scroll_to_cursor (view);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
|
||||
&start_iter);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static void
|
||||
do_find (XedSearchDialog *dialog,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedView *active_view;
|
||||
XedDocument *doc;
|
||||
gchar *search_text;
|
||||
const gchar *entry_text;
|
||||
gboolean match_case;
|
||||
gboolean entire_word;
|
||||
gboolean wrap_around;
|
||||
gboolean search_backwards;
|
||||
gboolean parse_escapes;
|
||||
guint flags = 0;
|
||||
guint old_flags = 0;
|
||||
gboolean found;
|
||||
|
||||
/* TODO: make the dialog insensitive when all the tabs are closed
|
||||
* and assert here that the view is not NULL */
|
||||
active_view = xed_window_get_active_view (window);
|
||||
if (active_view == NULL)
|
||||
return;
|
||||
|
||||
doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (active_view)));
|
||||
|
||||
match_case = xed_search_dialog_get_match_case (dialog);
|
||||
entire_word = xed_search_dialog_get_entire_word (dialog);
|
||||
search_backwards = xed_search_dialog_get_backwards (dialog);
|
||||
wrap_around = xed_search_dialog_get_wrap_around (dialog);
|
||||
parse_escapes = xed_search_dialog_get_parse_escapes (dialog);
|
||||
|
||||
if (!parse_escapes) {
|
||||
entry_text = xed_utils_escape_search_text (xed_search_dialog_get_search_text (dialog));
|
||||
} else {
|
||||
entry_text = xed_search_dialog_get_search_text (dialog);
|
||||
}
|
||||
|
||||
XED_SEARCH_SET_CASE_SENSITIVE (flags, match_case);
|
||||
XED_SEARCH_SET_ENTIRE_WORD (flags, entire_word);
|
||||
|
||||
search_text = xed_document_get_search_text (doc, &old_flags);
|
||||
|
||||
if ((search_text == NULL) ||
|
||||
(strcmp (search_text, entry_text) != 0) ||
|
||||
(flags != old_flags))
|
||||
{
|
||||
xed_document_set_search_text (doc, entry_text, flags);
|
||||
}
|
||||
|
||||
g_free (search_text);
|
||||
|
||||
found = run_search (active_view,
|
||||
wrap_around,
|
||||
search_backwards);
|
||||
|
||||
if (found)
|
||||
text_found (window, 0);
|
||||
else {
|
||||
if (!parse_escapes) {
|
||||
text_not_found (window, xed_utils_unescape_search_text (entry_text));
|
||||
} else {
|
||||
text_not_found (window, entry_text);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
|
||||
XED_SEARCH_DIALOG_REPLACE_RESPONSE,
|
||||
found);
|
||||
}
|
||||
|
||||
/* FIXME: move in xed-document.c and share it with xed-view */
|
||||
static gboolean
|
||||
get_selected_text (GtkTextBuffer *doc,
|
||||
gchar **selected_text,
|
||||
gint *len)
|
||||
{
|
||||
GtkTextIter start, end;
|
||||
|
||||
g_return_val_if_fail (selected_text != NULL, FALSE);
|
||||
g_return_val_if_fail (*selected_text == NULL, FALSE);
|
||||
|
||||
if (!gtk_text_buffer_get_selection_bounds (doc, &start, &end))
|
||||
{
|
||||
if (len != NULL)
|
||||
len = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*selected_text = gtk_text_buffer_get_slice (doc, &start, &end, TRUE);
|
||||
|
||||
if (len != NULL)
|
||||
*len = g_utf8_strlen (*selected_text, -1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
replace_selected_text (GtkTextBuffer *buffer,
|
||||
const gchar *replace)
|
||||
{
|
||||
g_return_if_fail (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL));
|
||||
g_return_if_fail (replace != NULL);
|
||||
|
||||
gtk_text_buffer_begin_user_action (buffer);
|
||||
|
||||
gtk_text_buffer_delete_selection (buffer, FALSE, TRUE);
|
||||
|
||||
gtk_text_buffer_insert_at_cursor (buffer, replace, strlen (replace));
|
||||
|
||||
gtk_text_buffer_end_user_action (buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
do_replace (XedSearchDialog *dialog,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedDocument *doc;
|
||||
const gchar *search_entry_text;
|
||||
const gchar *replace_entry_text;
|
||||
gchar *unescaped_search_text;
|
||||
gchar *unescaped_replace_text;
|
||||
gchar *selected_text = NULL;
|
||||
gboolean match_case;
|
||||
gboolean parse_escapes;
|
||||
|
||||
doc = xed_window_get_active_document (window);
|
||||
if (doc == NULL)
|
||||
return;
|
||||
|
||||
parse_escapes = xed_search_dialog_get_parse_escapes (dialog);
|
||||
if (!parse_escapes) {
|
||||
search_entry_text = xed_utils_escape_search_text (xed_search_dialog_get_search_text (dialog));
|
||||
} else {
|
||||
search_entry_text = xed_search_dialog_get_search_text (dialog);
|
||||
}
|
||||
g_return_if_fail ((search_entry_text) != NULL);
|
||||
g_return_if_fail ((*search_entry_text) != '\0');
|
||||
|
||||
/* replace text may be "", we just delete */
|
||||
if (!parse_escapes) {
|
||||
replace_entry_text = xed_utils_escape_search_text (xed_search_dialog_get_replace_text (dialog));
|
||||
} else {
|
||||
replace_entry_text = xed_search_dialog_get_replace_text (dialog);
|
||||
}
|
||||
g_return_if_fail ((replace_entry_text) != NULL);
|
||||
|
||||
unescaped_search_text = xed_utils_unescape_search_text (search_entry_text);
|
||||
|
||||
get_selected_text (GTK_TEXT_BUFFER (doc),
|
||||
&selected_text,
|
||||
NULL);
|
||||
|
||||
match_case = xed_search_dialog_get_match_case (dialog);
|
||||
|
||||
if ((selected_text == NULL) ||
|
||||
(match_case && (strcmp (selected_text, unescaped_search_text) != 0)) ||
|
||||
(!match_case && !g_utf8_caselessnmatch (selected_text,
|
||||
unescaped_search_text,
|
||||
strlen (selected_text),
|
||||
strlen (unescaped_search_text)) != 0))
|
||||
{
|
||||
do_find (dialog, window);
|
||||
g_free (unescaped_search_text);
|
||||
g_free (selected_text);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unescaped_replace_text = xed_utils_unescape_search_text (replace_entry_text);
|
||||
replace_selected_text (GTK_TEXT_BUFFER (doc), unescaped_replace_text);
|
||||
|
||||
g_free (unescaped_search_text);
|
||||
g_free (selected_text);
|
||||
g_free (unescaped_replace_text);
|
||||
|
||||
do_find (dialog, window);
|
||||
}
|
||||
|
||||
static void
|
||||
do_replace_all (XedSearchDialog *dialog,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedView *active_view;
|
||||
XedDocument *doc;
|
||||
const gchar *search_entry_text;
|
||||
const gchar *replace_entry_text;
|
||||
gboolean match_case;
|
||||
gboolean entire_word;
|
||||
gboolean parse_escapes;
|
||||
guint flags = 0;
|
||||
gint count;
|
||||
|
||||
active_view = xed_window_get_active_view (window);
|
||||
if (active_view == NULL)
|
||||
return;
|
||||
|
||||
doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (active_view)));
|
||||
|
||||
parse_escapes = xed_search_dialog_get_parse_escapes (dialog);
|
||||
if (!parse_escapes) {
|
||||
search_entry_text = xed_utils_escape_search_text(xed_search_dialog_get_search_text (dialog));
|
||||
} else {
|
||||
search_entry_text = xed_search_dialog_get_search_text (dialog);
|
||||
}
|
||||
g_return_if_fail ((search_entry_text) != NULL);
|
||||
g_return_if_fail ((*search_entry_text) != '\0');
|
||||
|
||||
/* replace text may be "", we just delete all occurrencies */
|
||||
if (!parse_escapes) {
|
||||
replace_entry_text = xed_utils_escape_search_text (xed_search_dialog_get_replace_text (dialog));
|
||||
} else {
|
||||
replace_entry_text = xed_search_dialog_get_replace_text (dialog);
|
||||
}
|
||||
g_return_if_fail ((replace_entry_text) != NULL);
|
||||
|
||||
match_case = xed_search_dialog_get_match_case (dialog);
|
||||
entire_word = xed_search_dialog_get_entire_word (dialog);
|
||||
|
||||
XED_SEARCH_SET_CASE_SENSITIVE (flags, match_case);
|
||||
XED_SEARCH_SET_ENTIRE_WORD (flags, entire_word);
|
||||
|
||||
count = xed_document_replace_all (doc,
|
||||
search_entry_text,
|
||||
replace_entry_text,
|
||||
flags);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
text_found (window, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!parse_escapes) {
|
||||
text_not_found (window, xed_utils_unescape_search_text (search_entry_text));
|
||||
} else {
|
||||
text_not_found (window, search_entry_text);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
|
||||
XED_SEARCH_DIALOG_REPLACE_RESPONSE,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
search_dialog_response_cb (XedSearchDialog *dialog,
|
||||
gint response_id,
|
||||
XedWindow *window)
|
||||
{
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
switch (response_id)
|
||||
{
|
||||
case XED_SEARCH_DIALOG_FIND_RESPONSE:
|
||||
do_find (dialog, window);
|
||||
break;
|
||||
case XED_SEARCH_DIALOG_REPLACE_RESPONSE:
|
||||
do_replace (dialog, window);
|
||||
break;
|
||||
case XED_SEARCH_DIALOG_REPLACE_ALL_RESPONSE:
|
||||
do_replace_all (dialog, window);
|
||||
break;
|
||||
default:
|
||||
last_search_data_store_position (dialog);
|
||||
gtk_widget_hide (GTK_WIDGET (dialog));
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
search_dialog_delete_event_cb (GtkWidget *widget,
|
||||
GdkEventAny *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
/* prevent destruction */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
search_dialog_destroyed (XedWindow *window,
|
||||
XedSearchDialog *dialog)
|
||||
{
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
g_object_set_data (G_OBJECT (window),
|
||||
XED_SEARCH_DIALOG_KEY,
|
||||
NULL);
|
||||
g_object_set_data (G_OBJECT (dialog),
|
||||
XED_LAST_SEARCH_DATA_KEY,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_dialog (XedWindow *window, gboolean show_replace)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = xed_search_dialog_new (GTK_WINDOW (window), show_replace);
|
||||
|
||||
g_signal_connect (dialog,
|
||||
"response",
|
||||
G_CALLBACK (search_dialog_response_cb),
|
||||
window);
|
||||
g_signal_connect (dialog,
|
||||
"delete-event",
|
||||
G_CALLBACK (search_dialog_delete_event_cb),
|
||||
NULL);
|
||||
|
||||
g_object_set_data (G_OBJECT (window),
|
||||
XED_SEARCH_DIALOG_KEY,
|
||||
dialog);
|
||||
|
||||
g_object_weak_ref (G_OBJECT (dialog),
|
||||
(GWeakNotify) search_dialog_destroyed,
|
||||
window);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_search_find (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
gpointer data;
|
||||
GtkWidget *search_dialog;
|
||||
XedDocument *doc;
|
||||
gboolean selection_exists;
|
||||
gboolean parse_escapes;
|
||||
gchar *find_text = NULL;
|
||||
const gchar *search_text = NULL;
|
||||
gint sel_len;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
data = g_object_get_data (G_OBJECT (window), XED_SEARCH_DIALOG_KEY);
|
||||
|
||||
if (data == NULL)
|
||||
{
|
||||
search_dialog = create_dialog (window, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCH_DIALOG (data));
|
||||
|
||||
search_dialog = GTK_WIDGET (data);
|
||||
|
||||
/* turn the dialog into a find dialog if needed */
|
||||
if (xed_search_dialog_get_show_replace (XED_SEARCH_DIALOG (search_dialog)))
|
||||
xed_search_dialog_set_show_replace (XED_SEARCH_DIALOG (search_dialog),
|
||||
FALSE);
|
||||
}
|
||||
|
||||
doc = xed_window_get_active_document (window);
|
||||
g_return_if_fail (doc != NULL);
|
||||
|
||||
selection_exists = get_selected_text (GTK_TEXT_BUFFER (doc),
|
||||
&find_text,
|
||||
&sel_len);
|
||||
|
||||
if (selection_exists && find_text != NULL && sel_len < 80)
|
||||
{
|
||||
/*
|
||||
* Special case: if the currently selected text
|
||||
* is the same as the unescaped search text and
|
||||
* escape sequence parsing is activated, use the
|
||||
* same old search text. (Without this, if you e.g.
|
||||
* search for '\n' in escaped mode and then open
|
||||
* the search dialog again, you'll get an unprintable
|
||||
* single-character literal '\n' in the "search for"
|
||||
* box).
|
||||
*/
|
||||
parse_escapes = xed_search_dialog_get_parse_escapes (XED_SEARCH_DIALOG (search_dialog));
|
||||
search_text = xed_search_dialog_get_search_text (XED_SEARCH_DIALOG (search_dialog));
|
||||
if (!(search_text != NULL
|
||||
&& !strcmp(xed_utils_unescape_search_text(search_text), find_text)
|
||||
&& parse_escapes)) {
|
||||
/* General case */
|
||||
xed_search_dialog_set_search_text (XED_SEARCH_DIALOG (search_dialog),
|
||||
find_text);
|
||||
}
|
||||
g_free (find_text);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_free (find_text);
|
||||
}
|
||||
|
||||
gtk_widget_show (search_dialog);
|
||||
last_search_data_restore_position (XED_SEARCH_DIALOG (search_dialog));
|
||||
xed_search_dialog_present_with_time (XED_SEARCH_DIALOG (search_dialog),
|
||||
GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_search_replace (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
gpointer data;
|
||||
GtkWidget *replace_dialog;
|
||||
XedDocument *doc;
|
||||
gboolean selection_exists;
|
||||
gboolean parse_escapes;
|
||||
gchar *find_text = NULL;
|
||||
const gchar *search_text = NULL;
|
||||
gint sel_len;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
data = g_object_get_data (G_OBJECT (window), XED_SEARCH_DIALOG_KEY);
|
||||
|
||||
if (data == NULL)
|
||||
{
|
||||
replace_dialog = create_dialog (window, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_return_if_fail (XED_IS_SEARCH_DIALOG (data));
|
||||
|
||||
replace_dialog = GTK_WIDGET (data);
|
||||
|
||||
/* turn the dialog into a find dialog if needed */
|
||||
if (!xed_search_dialog_get_show_replace (XED_SEARCH_DIALOG (replace_dialog)))
|
||||
xed_search_dialog_set_show_replace (XED_SEARCH_DIALOG (replace_dialog),
|
||||
TRUE);
|
||||
}
|
||||
|
||||
doc = xed_window_get_active_document (window);
|
||||
g_return_if_fail (doc != NULL);
|
||||
|
||||
selection_exists = get_selected_text (GTK_TEXT_BUFFER (doc),
|
||||
&find_text,
|
||||
&sel_len);
|
||||
|
||||
if (selection_exists && find_text != NULL && sel_len < 80)
|
||||
{
|
||||
/*
|
||||
* Special case: if the currently selected text
|
||||
* is the same as the unescaped search text and
|
||||
* escape sequence parsing is activated, use the
|
||||
* same old search text. (Without this, if you e.g.
|
||||
* search for '\n' in escaped mode and then open
|
||||
* the search dialog again, you'll get an unprintable
|
||||
* single-character literal '\n' in the "search for"
|
||||
* box).
|
||||
*/
|
||||
parse_escapes = xed_search_dialog_get_parse_escapes (XED_SEARCH_DIALOG (replace_dialog));
|
||||
search_text = xed_search_dialog_get_search_text (XED_SEARCH_DIALOG (replace_dialog));
|
||||
if (!(search_text != NULL
|
||||
&& !strcmp(xed_utils_unescape_search_text(search_text), find_text)
|
||||
&& parse_escapes)) {
|
||||
/* General case */
|
||||
xed_search_dialog_set_search_text (XED_SEARCH_DIALOG (replace_dialog),
|
||||
find_text);
|
||||
}
|
||||
g_free (find_text);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_free (find_text);
|
||||
}
|
||||
|
||||
gtk_widget_show (replace_dialog);
|
||||
last_search_data_restore_position (XED_SEARCH_DIALOG (replace_dialog));
|
||||
xed_search_dialog_present_with_time (XED_SEARCH_DIALOG (replace_dialog),
|
||||
GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
static void
|
||||
do_find_again (XedWindow *window,
|
||||
gboolean backward)
|
||||
{
|
||||
XedView *active_view;
|
||||
gboolean wrap_around = TRUE;
|
||||
gpointer data;
|
||||
|
||||
active_view = xed_window_get_active_view (window);
|
||||
g_return_if_fail (active_view != NULL);
|
||||
|
||||
data = g_object_get_data (G_OBJECT (window), XED_SEARCH_DIALOG_KEY);
|
||||
|
||||
if (data != NULL)
|
||||
wrap_around = xed_search_dialog_get_wrap_around (XED_SEARCH_DIALOG (data));
|
||||
|
||||
run_search (active_view,
|
||||
wrap_around,
|
||||
backward);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_search_find_next (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
do_find_again (window, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_search_find_prev (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
do_find_again (window, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_search_clear_highlight (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedDocument *doc;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
doc = xed_window_get_active_document (window);
|
||||
xed_document_set_search_text (XED_DOCUMENT (doc),
|
||||
"",
|
||||
XED_SEARCH_DONT_SET_FLAGS);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_search_goto_line (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedView *active_view;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
active_view = xed_window_get_active_view (window);
|
||||
if (active_view == NULL)
|
||||
return;
|
||||
|
||||
/* Focus the view if needed: we need to focus the view otherwise
|
||||
activating the binding for goto line has no effect */
|
||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||
|
||||
|
||||
/* goto line is builtin in XedView, just activate
|
||||
* the corrisponding binding.
|
||||
*/
|
||||
gtk_bindings_activate (GTK_OBJECT (active_view),
|
||||
GDK_KEY_i,
|
||||
GDK_CONTROL_MASK);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_search_incremental_search (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
XedView *active_view;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
active_view = xed_window_get_active_view (window);
|
||||
if (active_view == NULL)
|
||||
return;
|
||||
|
||||
/* Focus the view if needed: we need to focus the view otherwise
|
||||
activating the binding for incremental search has no effect */
|
||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||
|
||||
/* incremental search is builtin in XedView, just activate
|
||||
* the corrisponding binding.
|
||||
*/
|
||||
gtk_bindings_activate (GTK_OBJECT (active_view),
|
||||
GDK_KEY_k,
|
||||
GDK_CONTROL_MASK);
|
||||
}
|
||||
154
xed/xed-commands-view.c
Normal file
154
xed/xed-commands-view.c
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* xed-view-commands.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
|
||||
* Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 1998-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "xed-commands.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-window.h"
|
||||
#include "xed-window-private.h"
|
||||
|
||||
|
||||
void
|
||||
_xed_cmd_view_show_toolbar (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
gboolean visible;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
visible = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
|
||||
|
||||
if (visible)
|
||||
gtk_widget_show (window->priv->toolbar);
|
||||
else
|
||||
gtk_widget_hide (window->priv->toolbar);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_view_show_statusbar (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
gboolean visible;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
visible = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
|
||||
|
||||
if (visible)
|
||||
gtk_widget_show (window->priv->statusbar);
|
||||
else
|
||||
gtk_widget_hide (window->priv->statusbar);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_view_show_side_pane (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
gboolean visible;
|
||||
XedPanel *panel;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
visible = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
|
||||
|
||||
panel = xed_window_get_side_panel (window);
|
||||
|
||||
if (visible)
|
||||
{
|
||||
gtk_widget_show (GTK_WIDGET (panel));
|
||||
gtk_widget_grab_focus (GTK_WIDGET (panel));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_hide (GTK_WIDGET (panel));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_view_show_bottom_pane (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
gboolean visible;
|
||||
XedPanel *panel;
|
||||
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
visible = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
|
||||
|
||||
panel = xed_window_get_bottom_panel (window);
|
||||
|
||||
if (visible)
|
||||
{
|
||||
gtk_widget_show (GTK_WIDGET (panel));
|
||||
gtk_widget_grab_focus (GTK_WIDGET (panel));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_hide (GTK_WIDGET (panel));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_view_toggle_fullscreen_mode (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
xed_debug (DEBUG_COMMANDS);
|
||||
|
||||
if (_xed_window_is_fullscreen (window))
|
||||
_xed_window_unfullscreen (window);
|
||||
else
|
||||
_xed_window_fullscreen (window);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_cmd_view_leave_fullscreen_mode (GtkAction *action,
|
||||
XedWindow *window)
|
||||
{
|
||||
GtkAction *view_action;
|
||||
|
||||
view_action = gtk_action_group_get_action (window->priv->always_sensitive_action_group,
|
||||
"ViewFullscreen");
|
||||
g_signal_handlers_block_by_func
|
||||
(view_action, G_CALLBACK (_xed_cmd_view_toggle_fullscreen_mode),
|
||||
window);
|
||||
gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_action),
|
||||
FALSE);
|
||||
_xed_window_unfullscreen (window);
|
||||
g_signal_handlers_unblock_by_func
|
||||
(view_action, G_CALLBACK (_xed_cmd_view_toggle_fullscreen_mode),
|
||||
window);
|
||||
}
|
||||
159
xed/xed-commands.h
Normal file
159
xed/xed-commands.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* xed-commands.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
|
||||
* Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 1998-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_COMMANDS_H__
|
||||
#define __XED_COMMANDS_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <xed/xed-window.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* Do nothing if URI does not exist */
|
||||
void xed_commands_load_uri (XedWindow *window,
|
||||
const gchar *uri,
|
||||
const XedEncoding *encoding,
|
||||
gint line_pos);
|
||||
|
||||
/* Ignore non-existing URIs */
|
||||
gint xed_commands_load_uris (XedWindow *window,
|
||||
const GSList *uris,
|
||||
const XedEncoding *encoding,
|
||||
gint line_pos);
|
||||
|
||||
void xed_commands_save_document (XedWindow *window,
|
||||
XedDocument *document);
|
||||
|
||||
void xed_commands_save_all_documents (XedWindow *window);
|
||||
|
||||
/*
|
||||
* Non-exported functions
|
||||
*/
|
||||
|
||||
/* Create titled documens for non-existing URIs */
|
||||
gint _xed_cmd_load_files_from_prompt (XedWindow *window,
|
||||
GSList *files,
|
||||
const XedEncoding *encoding,
|
||||
gint line_pos);
|
||||
|
||||
void _xed_cmd_file_new (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_file_open (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_file_save (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_file_save_as (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_file_save_all (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_file_revert (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_file_open_uri (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_file_print_preview (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_file_print (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_file_close (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_file_close_all (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_file_quit (GtkAction *action,
|
||||
XedWindow *window);
|
||||
|
||||
void _xed_cmd_edit_undo (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_edit_redo (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_edit_cut (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_edit_copy (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_edit_paste (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_edit_delete (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_edit_select_all (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_edit_preferences (GtkAction *action,
|
||||
XedWindow *window);
|
||||
|
||||
void _xed_cmd_view_show_toolbar (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_view_show_statusbar (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_view_show_side_pane (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_view_show_bottom_pane (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_view_toggle_fullscreen_mode (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_view_leave_fullscreen_mode (GtkAction *action,
|
||||
XedWindow *window);
|
||||
|
||||
void _xed_cmd_search_find (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_search_find_next (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_search_find_prev (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_search_replace (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_search_clear_highlight (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_search_goto_line (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_search_incremental_search (GtkAction *action,
|
||||
XedWindow *window);
|
||||
|
||||
void _xed_cmd_documents_previous_document (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_documents_next_document (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_documents_move_to_new_window (GtkAction *action,
|
||||
XedWindow *window);
|
||||
|
||||
void _xed_cmd_help_contents (GtkAction *action,
|
||||
XedWindow *window);
|
||||
void _xed_cmd_help_about (GtkAction *action,
|
||||
XedWindow *window);
|
||||
|
||||
void _xed_cmd_file_close_tab (XedTab *tab,
|
||||
XedWindow *window);
|
||||
|
||||
void _xed_cmd_file_save_documents_list (XedWindow *window,
|
||||
GList *docs);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_COMMANDS_H__ */
|
||||
158
xed/xed-debug.c
Normal file
158
xed/xed-debug.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* xed-debug.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
|
||||
* Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
|
||||
* Copyright (C) 2002 - 2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 1998-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "xed-debug.h"
|
||||
|
||||
#define ENABLE_PROFILING
|
||||
|
||||
#ifdef ENABLE_PROFILING
|
||||
static GTimer *timer = NULL;
|
||||
static gdouble last = 0.0;
|
||||
#endif
|
||||
|
||||
static XedDebugSection debug = XED_NO_DEBUG;
|
||||
|
||||
void
|
||||
xed_debug_init (void)
|
||||
{
|
||||
if (g_getenv ("XED_DEBUG") != NULL)
|
||||
{
|
||||
/* enable all debugging */
|
||||
debug = ~XED_NO_DEBUG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (g_getenv ("XED_DEBUG_VIEW") != NULL)
|
||||
debug = debug | XED_DEBUG_VIEW;
|
||||
if (g_getenv ("XED_DEBUG_SEARCH") != NULL)
|
||||
debug = debug | XED_DEBUG_SEARCH;
|
||||
if (g_getenv ("XED_DEBUG_PREFS") != NULL)
|
||||
debug = debug | XED_DEBUG_PREFS;
|
||||
if (g_getenv ("XED_DEBUG_PRINT") != NULL)
|
||||
debug = debug | XED_DEBUG_PRINT;
|
||||
if (g_getenv ("XED_DEBUG_PLUGINS") != NULL)
|
||||
debug = debug | XED_DEBUG_PLUGINS;
|
||||
if (g_getenv ("XED_DEBUG_TAB") != NULL)
|
||||
debug = debug | XED_DEBUG_TAB;
|
||||
if (g_getenv ("XED_DEBUG_DOCUMENT") != NULL)
|
||||
debug = debug | XED_DEBUG_DOCUMENT;
|
||||
if (g_getenv ("XED_DEBUG_COMMANDS") != NULL)
|
||||
debug = debug | XED_DEBUG_COMMANDS;
|
||||
if (g_getenv ("XED_DEBUG_APP") != NULL)
|
||||
debug = debug | XED_DEBUG_APP;
|
||||
if (g_getenv ("XED_DEBUG_SESSION") != NULL)
|
||||
debug = debug | XED_DEBUG_SESSION;
|
||||
if (g_getenv ("XED_DEBUG_UTILS") != NULL)
|
||||
debug = debug | XED_DEBUG_UTILS;
|
||||
if (g_getenv ("XED_DEBUG_METADATA") != NULL)
|
||||
debug = debug | XED_DEBUG_METADATA;
|
||||
if (g_getenv ("XED_DEBUG_WINDOW") != NULL)
|
||||
debug = debug | XED_DEBUG_WINDOW;
|
||||
if (g_getenv ("XED_DEBUG_LOADER") != NULL)
|
||||
debug = debug | XED_DEBUG_LOADER;
|
||||
if (g_getenv ("XED_DEBUG_SAVER") != NULL)
|
||||
debug = debug | XED_DEBUG_SAVER;
|
||||
|
||||
out:
|
||||
|
||||
#ifdef ENABLE_PROFILING
|
||||
if (debug != XED_NO_DEBUG)
|
||||
timer = g_timer_new ();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
xed_debug_message (XedDebugSection section,
|
||||
const gchar *file,
|
||||
gint line,
|
||||
const gchar *function,
|
||||
const gchar *format, ...)
|
||||
{
|
||||
if (G_UNLIKELY (debug & section))
|
||||
{
|
||||
#ifdef ENABLE_PROFILING
|
||||
gdouble seconds;
|
||||
g_return_if_fail (timer != NULL);
|
||||
#endif
|
||||
|
||||
va_list args;
|
||||
gchar *msg;
|
||||
|
||||
g_return_if_fail (format != NULL);
|
||||
|
||||
va_start (args, format);
|
||||
msg = g_strdup_vprintf (format, args);
|
||||
va_end (args);
|
||||
|
||||
#ifdef ENABLE_PROFILING
|
||||
seconds = g_timer_elapsed (timer, NULL);
|
||||
g_print ("[%f (%f)] %s:%d (%s) %s\n",
|
||||
seconds, seconds - last, file, line, function, msg);
|
||||
last = seconds;
|
||||
#else
|
||||
g_print ("%s:%d (%s) %s\n", file, line, function, msg);
|
||||
#endif
|
||||
|
||||
fflush (stdout);
|
||||
|
||||
g_free (msg);
|
||||
}
|
||||
}
|
||||
|
||||
void xed_debug (XedDebugSection section,
|
||||
const gchar *file,
|
||||
gint line,
|
||||
const gchar *function)
|
||||
{
|
||||
if (G_UNLIKELY (debug & section))
|
||||
{
|
||||
#ifdef ENABLE_PROFILING
|
||||
gdouble seconds;
|
||||
|
||||
g_return_if_fail (timer != NULL);
|
||||
|
||||
seconds = g_timer_elapsed (timer, NULL);
|
||||
g_print ("[%f (%f)] %s:%d (%s)\n",
|
||||
seconds, seconds - last, file, line, function);
|
||||
last = seconds;
|
||||
#else
|
||||
g_print ("%s:%d (%s)\n", file, line, function);
|
||||
#endif
|
||||
fflush (stdout);
|
||||
}
|
||||
}
|
||||
94
xed/xed-debug.h
Normal file
94
xed/xed-debug.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* xed-debug.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
|
||||
* Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
|
||||
* Copyright (C) 2002 - 2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 1998-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_DEBUG_H__
|
||||
#define __XED_DEBUG_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/*
|
||||
* Set an environmental var of the same name to turn on
|
||||
* debugging output. Setting XED_DEBUG will turn on all
|
||||
* sections.
|
||||
*/
|
||||
typedef enum {
|
||||
XED_NO_DEBUG = 0,
|
||||
XED_DEBUG_VIEW = 1 << 0,
|
||||
XED_DEBUG_SEARCH = 1 << 1,
|
||||
XED_DEBUG_PRINT = 1 << 2,
|
||||
XED_DEBUG_PREFS = 1 << 3,
|
||||
XED_DEBUG_PLUGINS = 1 << 4,
|
||||
XED_DEBUG_TAB = 1 << 5,
|
||||
XED_DEBUG_DOCUMENT = 1 << 6,
|
||||
XED_DEBUG_COMMANDS = 1 << 7,
|
||||
XED_DEBUG_APP = 1 << 8,
|
||||
XED_DEBUG_SESSION = 1 << 9,
|
||||
XED_DEBUG_UTILS = 1 << 10,
|
||||
XED_DEBUG_METADATA = 1 << 11,
|
||||
XED_DEBUG_WINDOW = 1 << 12,
|
||||
XED_DEBUG_LOADER = 1 << 13,
|
||||
XED_DEBUG_SAVER = 1 << 14
|
||||
} XedDebugSection;
|
||||
|
||||
|
||||
/* FIXME this is an issue for introspection */
|
||||
#define DEBUG_VIEW XED_DEBUG_VIEW, __FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_SEARCH XED_DEBUG_SEARCH, __FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_PRINT XED_DEBUG_PRINT, __FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_PREFS XED_DEBUG_PREFS, __FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_PLUGINS XED_DEBUG_PLUGINS, __FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_TAB XED_DEBUG_TAB, __FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_DOCUMENT XED_DEBUG_DOCUMENT,__FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_COMMANDS XED_DEBUG_COMMANDS,__FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_APP XED_DEBUG_APP, __FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_SESSION XED_DEBUG_SESSION, __FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_UTILS XED_DEBUG_UTILS, __FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_METADATA XED_DEBUG_METADATA,__FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_WINDOW XED_DEBUG_WINDOW, __FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_LOADER XED_DEBUG_LOADER, __FILE__, __LINE__, G_STRFUNC
|
||||
#define DEBUG_SAVER XED_DEBUG_SAVER, __FILE__, __LINE__, G_STRFUNC
|
||||
|
||||
void xed_debug_init (void);
|
||||
|
||||
void xed_debug (XedDebugSection section,
|
||||
const gchar *file,
|
||||
gint line,
|
||||
const gchar *function);
|
||||
|
||||
void xed_debug_message (XedDebugSection section,
|
||||
const gchar *file,
|
||||
gint line,
|
||||
const gchar *function,
|
||||
const gchar *format, ...) G_GNUC_PRINTF(5, 6);
|
||||
|
||||
|
||||
#endif /* __XED_DEBUG_H__ */
|
||||
123
xed/xed-dirs.c
Normal file
123
xed/xed-dirs.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* xed-dirs.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2008 Ignacio Casal Quinteiro
|
||||
* Copyright (C) 2011 Perberos
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "xed-dirs.h"
|
||||
|
||||
gchar* xed_dirs_get_user_config_dir(void)
|
||||
{
|
||||
gchar* config_dir = NULL;
|
||||
|
||||
config_dir = g_build_filename(g_get_user_config_dir(), "xed", NULL);
|
||||
|
||||
return config_dir;
|
||||
}
|
||||
|
||||
gchar* xed_dirs_get_user_cache_dir(void)
|
||||
{
|
||||
const gchar* cache_dir;
|
||||
|
||||
cache_dir = g_get_user_cache_dir();
|
||||
|
||||
return g_build_filename(cache_dir, "xed", NULL);
|
||||
}
|
||||
|
||||
gchar* xed_dirs_get_user_plugins_dir(void)
|
||||
{
|
||||
gchar* plugin_dir;
|
||||
|
||||
plugin_dir = g_build_filename(g_get_user_data_dir(), "xed", "plugins", NULL);
|
||||
|
||||
return plugin_dir;
|
||||
}
|
||||
|
||||
gchar* xed_dirs_get_user_accels_file(void)
|
||||
{
|
||||
gchar* accels = NULL;
|
||||
gchar *config_dir = NULL;
|
||||
|
||||
config_dir = xed_dirs_get_user_config_dir();
|
||||
accels = g_build_filename(config_dir, "accels", NULL);
|
||||
|
||||
g_free(config_dir);
|
||||
|
||||
return accels;
|
||||
}
|
||||
|
||||
gchar* xed_dirs_get_xed_data_dir(void)
|
||||
{
|
||||
return g_build_filename(DATADIR, "xed", NULL);
|
||||
}
|
||||
|
||||
gchar* xed_dirs_get_xed_locale_dir(void)
|
||||
{
|
||||
return g_build_filename(DATADIR, "locale", NULL);
|
||||
}
|
||||
|
||||
gchar* xed_dirs_get_xed_lib_dir(void)
|
||||
{
|
||||
return g_build_filename(LIBDIR, "xed", NULL);
|
||||
}
|
||||
|
||||
gchar* xed_dirs_get_xed_plugins_dir(void)
|
||||
{
|
||||
gchar* lib_dir;
|
||||
gchar* plugin_dir;
|
||||
|
||||
lib_dir = xed_dirs_get_xed_lib_dir();
|
||||
|
||||
plugin_dir = g_build_filename(lib_dir, "plugins", NULL);
|
||||
g_free(lib_dir);
|
||||
|
||||
return plugin_dir;
|
||||
}
|
||||
|
||||
gchar* xed_dirs_get_xed_plugin_loaders_dir(void)
|
||||
{
|
||||
gchar* lib_dir;
|
||||
gchar* loader_dir;
|
||||
|
||||
lib_dir = xed_dirs_get_xed_lib_dir();
|
||||
|
||||
loader_dir = g_build_filename(lib_dir, "plugin-loaders", NULL);
|
||||
g_free(lib_dir);
|
||||
|
||||
return loader_dir;
|
||||
}
|
||||
|
||||
gchar* xed_dirs_get_ui_file(const gchar* file)
|
||||
{
|
||||
gchar* datadir;
|
||||
gchar* ui_file;
|
||||
|
||||
g_return_val_if_fail(file != NULL, NULL);
|
||||
|
||||
datadir = xed_dirs_get_xed_data_dir();
|
||||
ui_file = g_build_filename(datadir, "ui", file, NULL);
|
||||
g_free(datadir);
|
||||
|
||||
return ui_file;
|
||||
}
|
||||
54
xed/xed-dirs.h
Normal file
54
xed/xed-dirs.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* xed-dirs.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2008 Ignacio Casal Quinteiro
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __XED_DIRS_H__
|
||||
#define __XED_DIRS_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gchar *xed_dirs_get_user_config_dir (void);
|
||||
|
||||
gchar *xed_dirs_get_user_cache_dir (void);
|
||||
|
||||
gchar *xed_dirs_get_user_plugins_dir (void);
|
||||
|
||||
gchar *xed_dirs_get_user_accels_file (void);
|
||||
|
||||
gchar *xed_dirs_get_xed_data_dir (void);
|
||||
|
||||
gchar *xed_dirs_get_xed_locale_dir (void);
|
||||
|
||||
gchar *xed_dirs_get_xed_lib_dir (void);
|
||||
|
||||
gchar *xed_dirs_get_xed_plugins_dir (void);
|
||||
|
||||
gchar *xed_dirs_get_xed_plugin_loaders_dir
|
||||
(void);
|
||||
|
||||
gchar *xed_dirs_get_ui_file (const gchar *file);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_DIRS_H__ */
|
||||
479
xed/xed-document-input-stream.c
Normal file
479
xed/xed-document-input-stream.c
Normal file
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
* xed-document-input-stream.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2010 - Ignacio Casal Quinteiro
|
||||
*
|
||||
* xed is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* xed is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with xed; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <gio/gio.h>
|
||||
#include <string.h>
|
||||
#include "xed-document-input-stream.h"
|
||||
#include "xed-enum-types.h"
|
||||
|
||||
/* NOTE: never use async methods on this stream, the stream is just
|
||||
* a wrapper around GtkTextBuffer api so that we can use GIO Stream
|
||||
* methods, but the undelying code operates on a GtkTextBuffer, so
|
||||
* there is no I/O involved and should be accessed only by the main
|
||||
* thread */
|
||||
|
||||
|
||||
G_DEFINE_TYPE (XedDocumentInputStream, xed_document_input_stream, G_TYPE_INPUT_STREAM);
|
||||
|
||||
struct _XedDocumentInputStreamPrivate
|
||||
{
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextMark *pos;
|
||||
gint bytes_partial;
|
||||
|
||||
XedDocumentNewlineType newline_type;
|
||||
|
||||
guint newline_added : 1;
|
||||
guint is_initialized : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_BUFFER,
|
||||
PROP_NEWLINE_TYPE
|
||||
};
|
||||
|
||||
static gssize xed_document_input_stream_read (GInputStream *stream,
|
||||
void *buffer,
|
||||
gsize count,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
static gboolean xed_document_input_stream_close (GInputStream *stream,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
static void
|
||||
xed_document_input_stream_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedDocumentInputStream *stream = XED_DOCUMENT_INPUT_STREAM (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BUFFER:
|
||||
stream->priv->buffer = GTK_TEXT_BUFFER (g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_NEWLINE_TYPE:
|
||||
stream->priv->newline_type = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_input_stream_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedDocumentInputStream *stream = XED_DOCUMENT_INPUT_STREAM (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BUFFER:
|
||||
g_value_set_object (value, stream->priv->buffer);
|
||||
break;
|
||||
|
||||
case PROP_NEWLINE_TYPE:
|
||||
g_value_set_enum (value, stream->priv->newline_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_input_stream_class_init (XedDocumentInputStreamClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (XedDocumentInputStreamPrivate));
|
||||
|
||||
gobject_class->get_property = xed_document_input_stream_get_property;
|
||||
gobject_class->set_property = xed_document_input_stream_set_property;
|
||||
|
||||
stream_class->read_fn = xed_document_input_stream_read;
|
||||
stream_class->close_fn = xed_document_input_stream_close;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_BUFFER,
|
||||
g_param_spec_object ("buffer",
|
||||
"Buffer",
|
||||
"The buffer which is read",
|
||||
GTK_TYPE_TEXT_BUFFER,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
/**
|
||||
* XedDocumentInputStream:newline-type:
|
||||
*
|
||||
* The :newline-type property determines what is considered
|
||||
* as a line ending when reading complete lines from the stream.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_NEWLINE_TYPE,
|
||||
g_param_spec_enum ("newline-type",
|
||||
"Newline type",
|
||||
"The accepted types of line ending",
|
||||
XED_TYPE_DOCUMENT_NEWLINE_TYPE,
|
||||
XED_DOCUMENT_NEWLINE_TYPE_LF,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_NAME |
|
||||
G_PARAM_STATIC_BLURB |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_input_stream_init (XedDocumentInputStream *stream)
|
||||
{
|
||||
stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
|
||||
XED_TYPE_DOCUMENT_INPUT_STREAM,
|
||||
XedDocumentInputStreamPrivate);
|
||||
}
|
||||
|
||||
static gsize
|
||||
get_new_line_size (XedDocumentInputStream *stream)
|
||||
{
|
||||
gsize ret;
|
||||
|
||||
switch (stream->priv->newline_type)
|
||||
{
|
||||
case XED_DOCUMENT_NEWLINE_TYPE_CR:
|
||||
case XED_DOCUMENT_NEWLINE_TYPE_LF:
|
||||
ret = 1;
|
||||
break;
|
||||
|
||||
case XED_DOCUMENT_NEWLINE_TYPE_CR_LF:
|
||||
ret = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_warn_if_reached ();
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_document_input_stream_new:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
*
|
||||
* Reads the data from @buffer.
|
||||
*
|
||||
* Returns: a new #GInputStream to read @buffer
|
||||
*/
|
||||
GInputStream *
|
||||
xed_document_input_stream_new (GtkTextBuffer *buffer,
|
||||
XedDocumentNewlineType type)
|
||||
{
|
||||
XedDocumentInputStream *stream;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
|
||||
|
||||
stream = g_object_new (XED_TYPE_DOCUMENT_INPUT_STREAM,
|
||||
"buffer", buffer,
|
||||
"newline-type", type,
|
||||
NULL);
|
||||
|
||||
return G_INPUT_STREAM (stream);
|
||||
}
|
||||
|
||||
gsize
|
||||
xed_document_input_stream_get_total_size (XedDocumentInputStream *stream)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_INPUT_STREAM (stream), 0);
|
||||
|
||||
return gtk_text_buffer_get_char_count (stream->priv->buffer);
|
||||
}
|
||||
|
||||
gsize
|
||||
xed_document_input_stream_tell (XedDocumentInputStream *stream)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_INPUT_STREAM (stream), 0);
|
||||
|
||||
/* FIXME: is this potentially inefficient? If yes, we could keep
|
||||
track of the offset internally, assuming the mark doesn't move
|
||||
during the operation */
|
||||
if (!stream->priv->is_initialized)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkTextIter iter;
|
||||
|
||||
gtk_text_buffer_get_iter_at_mark (stream->priv->buffer,
|
||||
&iter,
|
||||
stream->priv->pos);
|
||||
return gtk_text_iter_get_offset (&iter);
|
||||
}
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
get_new_line (XedDocumentInputStream *stream)
|
||||
{
|
||||
const gchar *ret;
|
||||
|
||||
switch (stream->priv->newline_type)
|
||||
{
|
||||
case XED_DOCUMENT_NEWLINE_TYPE_CR:
|
||||
ret = "\r";
|
||||
break;
|
||||
|
||||
case XED_DOCUMENT_NEWLINE_TYPE_LF:
|
||||
ret = "\n";
|
||||
break;
|
||||
|
||||
case XED_DOCUMENT_NEWLINE_TYPE_CR_LF:
|
||||
ret = "\r\n";
|
||||
break;
|
||||
|
||||
default:
|
||||
g_warn_if_reached ();
|
||||
ret = "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gsize
|
||||
read_line (XedDocumentInputStream *stream,
|
||||
gchar *outbuf,
|
||||
gsize space_left)
|
||||
{
|
||||
GtkTextIter start, next, end;
|
||||
gchar *buf;
|
||||
gint bytes; /* int since it's what iter_get_offset returns */
|
||||
gsize bytes_to_write, newline_size, read;
|
||||
const gchar *newline;
|
||||
gboolean is_last;
|
||||
|
||||
gtk_text_buffer_get_iter_at_mark (stream->priv->buffer,
|
||||
&start,
|
||||
stream->priv->pos);
|
||||
|
||||
if (gtk_text_iter_is_end (&start))
|
||||
return 0;
|
||||
|
||||
end = next = start;
|
||||
newline = get_new_line (stream);
|
||||
|
||||
/* Check needed for empty lines */
|
||||
if (!gtk_text_iter_ends_line (&end))
|
||||
gtk_text_iter_forward_to_line_end (&end);
|
||||
|
||||
gtk_text_iter_forward_line (&next);
|
||||
|
||||
buf = gtk_text_iter_get_slice (&start, &end);
|
||||
|
||||
/* the bytes of a line includes also the newline, so with the
|
||||
offsets we remove the newline and we add the new newline size */
|
||||
bytes = gtk_text_iter_get_bytes_in_line (&start) - stream->priv->bytes_partial;
|
||||
|
||||
/* bytes_in_line includes the newlines, so we remove that assuming that
|
||||
they are single byte characters */
|
||||
bytes = bytes - (gtk_text_iter_get_offset (&next) - gtk_text_iter_get_offset (&end));
|
||||
is_last = gtk_text_iter_is_end (&end);
|
||||
|
||||
/* bytes_to_write contains the amount of bytes we would like to write.
|
||||
This means its the amount of bytes in the line (without the newline
|
||||
in the buffer) + the amount of bytes for the newline we want to
|
||||
write (newline_size) */
|
||||
bytes_to_write = bytes;
|
||||
|
||||
/* do not add the new newline_size for the last line */
|
||||
newline_size = get_new_line_size (stream);
|
||||
if (!is_last)
|
||||
bytes_to_write += newline_size;
|
||||
|
||||
if (bytes_to_write > space_left)
|
||||
{
|
||||
gchar *ptr;
|
||||
gint char_offset;
|
||||
gint written;
|
||||
gsize to_write;
|
||||
|
||||
/* Here the line does not fit in the buffer, we thus write
|
||||
the amount of bytes we can still fit, storing the position
|
||||
for the next read with the mark. Do not try to write the
|
||||
new newline in this case, it will be handled in the next
|
||||
iteration */
|
||||
to_write = MIN (space_left, bytes);
|
||||
ptr = buf;
|
||||
written = 0;
|
||||
char_offset = 0;
|
||||
|
||||
while (written < to_write)
|
||||
{
|
||||
gint w;
|
||||
|
||||
ptr = g_utf8_next_char (ptr);
|
||||
w = (ptr - buf);
|
||||
if (w > to_write)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
written = w;
|
||||
++char_offset;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy (outbuf, buf, written);
|
||||
|
||||
/* Note: offset is one past what we wrote */
|
||||
gtk_text_iter_forward_chars (&start, char_offset);
|
||||
stream->priv->bytes_partial += written;
|
||||
read = written;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* First just copy the bytes without the newline */
|
||||
memcpy (outbuf, buf, bytes);
|
||||
|
||||
/* Then add the newline, but not for the last line */
|
||||
if (!is_last)
|
||||
{
|
||||
memcpy (outbuf + bytes, newline, newline_size);
|
||||
}
|
||||
|
||||
start = next;
|
||||
stream->priv->bytes_partial = 0;
|
||||
read = bytes_to_write;
|
||||
}
|
||||
|
||||
gtk_text_buffer_move_mark (stream->priv->buffer,
|
||||
stream->priv->pos,
|
||||
&start);
|
||||
|
||||
g_free (buf);
|
||||
return read;
|
||||
}
|
||||
|
||||
static gssize
|
||||
xed_document_input_stream_read (GInputStream *stream,
|
||||
void *buffer,
|
||||
gsize count,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
XedDocumentInputStream *dstream;
|
||||
GtkTextIter iter;
|
||||
gssize space_left, read, n;
|
||||
|
||||
dstream = XED_DOCUMENT_INPUT_STREAM (stream);
|
||||
|
||||
if (count < 6)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
|
||||
"Not enougth space in destination");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
return -1;
|
||||
|
||||
/* Initialize the mark to the first char in the text buffer */
|
||||
if (!dstream->priv->is_initialized)
|
||||
{
|
||||
gtk_text_buffer_get_start_iter (dstream->priv->buffer, &iter);
|
||||
dstream->priv->pos = gtk_text_buffer_create_mark (dstream->priv->buffer,
|
||||
NULL,
|
||||
&iter,
|
||||
FALSE);
|
||||
|
||||
dstream->priv->is_initialized = TRUE;
|
||||
}
|
||||
|
||||
space_left = count;
|
||||
read = 0;
|
||||
|
||||
do
|
||||
{
|
||||
n = read_line (dstream, buffer + read, space_left);
|
||||
read += n;
|
||||
space_left -= n;
|
||||
} while (space_left > 0 && n != 0 && dstream->priv->bytes_partial == 0);
|
||||
|
||||
/* Make sure that non-empty files are always terminated with \n (see bug #95676).
|
||||
* Note that we strip the trailing \n when loading the file */
|
||||
gtk_text_buffer_get_iter_at_mark (dstream->priv->buffer,
|
||||
&iter,
|
||||
dstream->priv->pos);
|
||||
|
||||
if (gtk_text_iter_is_end (&iter) &&
|
||||
!gtk_text_iter_is_start (&iter))
|
||||
{
|
||||
gssize newline_size;
|
||||
|
||||
newline_size = get_new_line_size (dstream);
|
||||
|
||||
if (space_left >= newline_size &&
|
||||
!dstream->priv->newline_added)
|
||||
{
|
||||
const gchar *newline;
|
||||
|
||||
newline = get_new_line (dstream);
|
||||
|
||||
memcpy (buffer + read, newline, newline_size);
|
||||
|
||||
read += newline_size;
|
||||
dstream->priv->newline_added = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xed_document_input_stream_close (GInputStream *stream,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
XedDocumentInputStream *dstream = XED_DOCUMENT_INPUT_STREAM (stream);
|
||||
|
||||
dstream->priv->newline_added = FALSE;
|
||||
|
||||
if (dstream->priv->is_initialized)
|
||||
{
|
||||
gtk_text_buffer_delete_mark (dstream->priv->buffer, dstream->priv->pos);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
68
xed/xed-document-input-stream.h
Normal file
68
xed/xed-document-input-stream.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* xed-document-input-stream.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2010 - Ignacio Casal Quinteiro
|
||||
*
|
||||
* xed is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* xed is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with xed; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __XED_DOCUMENT_INPUT_STREAM_H__
|
||||
#define __XED_DOCUMENT_INPUT_STREAM_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "xed-document.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_DOCUMENT_INPUT_STREAM (xed_document_input_stream_get_type ())
|
||||
#define XED_DOCUMENT_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_DOCUMENT_INPUT_STREAM, XedDocumentInputStream))
|
||||
#define XED_DOCUMENT_INPUT_STREAM_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_DOCUMENT_INPUT_STREAM, XedDocumentInputStream const))
|
||||
#define XED_DOCUMENT_INPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_DOCUMENT_INPUT_STREAM, XedDocumentInputStreamClass))
|
||||
#define XED_IS_DOCUMENT_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_DOCUMENT_INPUT_STREAM))
|
||||
#define XED_IS_DOCUMENT_INPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_DOCUMENT_INPUT_STREAM))
|
||||
#define XED_DOCUMENT_INPUT_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_DOCUMENT_INPUT_STREAM, XedDocumentInputStreamClass))
|
||||
|
||||
typedef struct _XedDocumentInputStream XedDocumentInputStream;
|
||||
typedef struct _XedDocumentInputStreamClass XedDocumentInputStreamClass;
|
||||
typedef struct _XedDocumentInputStreamPrivate XedDocumentInputStreamPrivate;
|
||||
|
||||
struct _XedDocumentInputStream
|
||||
{
|
||||
GInputStream parent;
|
||||
|
||||
XedDocumentInputStreamPrivate *priv;
|
||||
};
|
||||
|
||||
struct _XedDocumentInputStreamClass
|
||||
{
|
||||
GInputStreamClass parent_class;
|
||||
};
|
||||
|
||||
GType xed_document_input_stream_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GInputStream *xed_document_input_stream_new (GtkTextBuffer *buffer,
|
||||
XedDocumentNewlineType type);
|
||||
|
||||
gsize xed_document_input_stream_get_total_size (XedDocumentInputStream *stream);
|
||||
|
||||
gsize xed_document_input_stream_tell (XedDocumentInputStream *stream);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_DOCUMENT_INPUT_STREAM_H__ */
|
||||
357
xed/xed-document-loader.c
Normal file
357
xed/xed-document-loader.c
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* xed-document-loader.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
* Copyright (C) 2007 - Paolo Maggi, Steve Frécinaux
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005-2007. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "xed-document-loader.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-metadata-manager.h"
|
||||
#include "xed-utils.h"
|
||||
#include "xed-marshal.h"
|
||||
#include "xed-enum-types.h"
|
||||
|
||||
/* Those are for the the xed_document_loader_new() factory */
|
||||
#include "xed-gio-document-loader.h"
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE(XedDocumentLoader, xed_document_loader, G_TYPE_OBJECT)
|
||||
|
||||
/* Signals */
|
||||
|
||||
enum {
|
||||
LOADING,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
/* Properties */
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DOCUMENT,
|
||||
PROP_URI,
|
||||
PROP_ENCODING,
|
||||
PROP_NEWLINE_TYPE
|
||||
};
|
||||
|
||||
static void
|
||||
xed_document_loader_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedDocumentLoader *loader = XED_DOCUMENT_LOADER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DOCUMENT:
|
||||
g_return_if_fail (loader->document == NULL);
|
||||
loader->document = g_value_get_object (value);
|
||||
break;
|
||||
case PROP_URI:
|
||||
g_return_if_fail (loader->uri == NULL);
|
||||
loader->uri = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_ENCODING:
|
||||
g_return_if_fail (loader->encoding == NULL);
|
||||
loader->encoding = g_value_get_boxed (value);
|
||||
break;
|
||||
case PROP_NEWLINE_TYPE:
|
||||
loader->auto_detected_newline_type = g_value_get_enum (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_loader_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedDocumentLoader *loader = XED_DOCUMENT_LOADER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DOCUMENT:
|
||||
g_value_set_object (value, loader->document);
|
||||
break;
|
||||
case PROP_URI:
|
||||
g_value_set_string (value, loader->uri);
|
||||
break;
|
||||
case PROP_ENCODING:
|
||||
g_value_set_boxed (value, xed_document_loader_get_encoding (loader));
|
||||
break;
|
||||
case PROP_NEWLINE_TYPE:
|
||||
g_value_set_enum (value, loader->auto_detected_newline_type);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_loader_finalize (GObject *object)
|
||||
{
|
||||
XedDocumentLoader *loader = XED_DOCUMENT_LOADER (object);
|
||||
|
||||
g_free (loader->uri);
|
||||
|
||||
if (loader->info)
|
||||
g_object_unref (loader->info);
|
||||
|
||||
G_OBJECT_CLASS (xed_document_loader_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_loader_dispose (GObject *object)
|
||||
{
|
||||
XedDocumentLoader *loader = XED_DOCUMENT_LOADER (object);
|
||||
|
||||
if (loader->info != NULL)
|
||||
{
|
||||
g_object_unref (loader->info);
|
||||
loader->info = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (xed_document_loader_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_loader_class_init (XedDocumentLoaderClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = xed_document_loader_finalize;
|
||||
object_class->dispose = xed_document_loader_dispose;
|
||||
object_class->get_property = xed_document_loader_get_property;
|
||||
object_class->set_property = xed_document_loader_set_property;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_DOCUMENT,
|
||||
g_param_spec_object ("document",
|
||||
"Document",
|
||||
"The XedDocument this XedDocumentLoader is associated with",
|
||||
XED_TYPE_DOCUMENT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_URI,
|
||||
g_param_spec_string ("uri",
|
||||
"URI",
|
||||
"The URI this XedDocumentLoader loads the document from",
|
||||
"",
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_ENCODING,
|
||||
g_param_spec_boxed ("encoding",
|
||||
"Encoding",
|
||||
"The encoding of the saved file",
|
||||
XED_TYPE_ENCODING,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_NEWLINE_TYPE,
|
||||
g_param_spec_enum ("newline-type",
|
||||
"Newline type",
|
||||
"The accepted types of line ending",
|
||||
XED_TYPE_DOCUMENT_NEWLINE_TYPE,
|
||||
XED_DOCUMENT_NEWLINE_TYPE_LF,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_NAME |
|
||||
G_PARAM_STATIC_BLURB));
|
||||
|
||||
signals[LOADING] =
|
||||
g_signal_new ("loading",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (XedDocumentLoaderClass, loading),
|
||||
NULL, NULL,
|
||||
xed_marshal_VOID__BOOLEAN_POINTER,
|
||||
G_TYPE_NONE,
|
||||
2,
|
||||
G_TYPE_BOOLEAN,
|
||||
G_TYPE_POINTER);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_loader_init (XedDocumentLoader *loader)
|
||||
{
|
||||
loader->used = FALSE;
|
||||
loader->auto_detected_newline_type = XED_DOCUMENT_NEWLINE_TYPE_DEFAULT;
|
||||
}
|
||||
|
||||
void
|
||||
xed_document_loader_loading (XedDocumentLoader *loader,
|
||||
gboolean completed,
|
||||
GError *error)
|
||||
{
|
||||
/* the object will be unrefed in the callback of the loading signal
|
||||
* (when completed == TRUE), so we need to prevent finalization.
|
||||
*/
|
||||
if (completed)
|
||||
{
|
||||
g_object_ref (loader);
|
||||
}
|
||||
|
||||
g_signal_emit (loader, signals[LOADING], 0, completed, error);
|
||||
|
||||
if (completed)
|
||||
{
|
||||
if (error == NULL)
|
||||
xed_debug_message (DEBUG_LOADER, "load completed");
|
||||
else
|
||||
xed_debug_message (DEBUG_LOADER, "load failed");
|
||||
|
||||
g_object_unref (loader);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is a factory method that returns an appopriate loader
|
||||
* for the given uri.
|
||||
*/
|
||||
XedDocumentLoader *
|
||||
xed_document_loader_new (XedDocument *doc,
|
||||
const gchar *uri,
|
||||
const XedEncoding *encoding)
|
||||
{
|
||||
XedDocumentLoader *loader;
|
||||
GType loader_type;
|
||||
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
|
||||
|
||||
/* At the moment we just use gio loader in all cases...
|
||||
* In the future it would be great to have a PolicyKit
|
||||
* loader to get permission to save systen files etc */
|
||||
loader_type = XED_TYPE_GIO_DOCUMENT_LOADER;
|
||||
|
||||
loader = XED_DOCUMENT_LOADER (g_object_new (loader_type,
|
||||
"document", doc,
|
||||
"uri", uri,
|
||||
"encoding", encoding,
|
||||
NULL));
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
||||
/* If enconding == NULL, the encoding will be autodetected */
|
||||
void
|
||||
xed_document_loader_load (XedDocumentLoader *loader)
|
||||
{
|
||||
xed_debug (DEBUG_LOADER);
|
||||
|
||||
g_return_if_fail (XED_IS_DOCUMENT_LOADER (loader));
|
||||
|
||||
/* the loader can be used just once, then it must be thrown away */
|
||||
g_return_if_fail (loader->used == FALSE);
|
||||
loader->used = TRUE;
|
||||
|
||||
XED_DOCUMENT_LOADER_GET_CLASS (loader)->load (loader);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_document_loader_cancel (XedDocumentLoader *loader)
|
||||
{
|
||||
xed_debug (DEBUG_LOADER);
|
||||
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_LOADER (loader), FALSE);
|
||||
|
||||
return XED_DOCUMENT_LOADER_GET_CLASS (loader)->cancel (loader);
|
||||
}
|
||||
|
||||
XedDocument *
|
||||
xed_document_loader_get_document (XedDocumentLoader *loader)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_LOADER (loader), NULL);
|
||||
|
||||
return loader->document;
|
||||
}
|
||||
|
||||
/* Returns STDIN_URI if loading from stdin */
|
||||
const gchar *
|
||||
xed_document_loader_get_uri (XedDocumentLoader *loader)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_LOADER (loader), NULL);
|
||||
|
||||
return loader->uri;
|
||||
}
|
||||
|
||||
goffset
|
||||
xed_document_loader_get_bytes_read (XedDocumentLoader *loader)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_LOADER (loader), 0);
|
||||
|
||||
return XED_DOCUMENT_LOADER_GET_CLASS (loader)->get_bytes_read (loader);
|
||||
}
|
||||
|
||||
const XedEncoding *
|
||||
xed_document_loader_get_encoding (XedDocumentLoader *loader)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_LOADER (loader), NULL);
|
||||
|
||||
if (loader->encoding != NULL)
|
||||
return loader->encoding;
|
||||
|
||||
g_return_val_if_fail (loader->auto_detected_encoding != NULL,
|
||||
xed_encoding_get_current ());
|
||||
|
||||
return loader->auto_detected_encoding;
|
||||
}
|
||||
|
||||
XedDocumentNewlineType
|
||||
xed_document_loader_get_newline_type (XedDocumentLoader *loader)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_LOADER (loader),
|
||||
XED_DOCUMENT_NEWLINE_TYPE_LF);
|
||||
|
||||
return loader->auto_detected_newline_type;
|
||||
}
|
||||
|
||||
GFileInfo *
|
||||
xed_document_loader_get_info (XedDocumentLoader *loader)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_LOADER (loader), NULL);
|
||||
|
||||
return loader->info;
|
||||
}
|
||||
130
xed/xed-document-loader.h
Normal file
130
xed/xed-document-loader.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* xed-document-loader.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
* Copyright (C) 2007 - Paolo Maggi, Steve Frécinaux
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005-2007. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_DOCUMENT_LOADER_H__
|
||||
#define __XED_DOCUMENT_LOADER_H__
|
||||
|
||||
#include <xed/xed-document.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_DOCUMENT_LOADER (xed_document_loader_get_type())
|
||||
#define XED_DOCUMENT_LOADER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_DOCUMENT_LOADER, XedDocumentLoader))
|
||||
#define XED_DOCUMENT_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_DOCUMENT_LOADER, XedDocumentLoaderClass))
|
||||
#define XED_IS_DOCUMENT_LOADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_DOCUMENT_LOADER))
|
||||
#define XED_IS_DOCUMENT_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_DOCUMENT_LOADER))
|
||||
#define XED_DOCUMENT_LOADER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_DOCUMENT_LOADER, XedDocumentLoaderClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedDocumentLoaderPrivate XedDocumentLoaderPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedDocumentLoader XedDocumentLoader;
|
||||
|
||||
struct _XedDocumentLoader
|
||||
{
|
||||
GObject object;
|
||||
|
||||
XedDocument *document;
|
||||
gboolean used;
|
||||
|
||||
/* Info on the current file */
|
||||
GFileInfo *info;
|
||||
gchar *uri;
|
||||
const XedEncoding *encoding;
|
||||
const XedEncoding *auto_detected_encoding;
|
||||
XedDocumentNewlineType auto_detected_newline_type;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedDocumentLoaderClass XedDocumentLoaderClass;
|
||||
|
||||
struct _XedDocumentLoaderClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* loading) (XedDocumentLoader *loader,
|
||||
gboolean completed,
|
||||
const GError *error);
|
||||
|
||||
/* VTable */
|
||||
void (* load) (XedDocumentLoader *loader);
|
||||
gboolean (* cancel) (XedDocumentLoader *loader);
|
||||
goffset (* get_bytes_read) (XedDocumentLoader *loader);
|
||||
};
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_document_loader_get_type (void) G_GNUC_CONST;
|
||||
|
||||
/* If enconding == NULL, the encoding will be autodetected */
|
||||
XedDocumentLoader *xed_document_loader_new (XedDocument *doc,
|
||||
const gchar *uri,
|
||||
const XedEncoding *encoding);
|
||||
|
||||
void xed_document_loader_loading (XedDocumentLoader *loader,
|
||||
gboolean completed,
|
||||
GError *error);
|
||||
|
||||
void xed_document_loader_load (XedDocumentLoader *loader);
|
||||
#if 0
|
||||
gboolean xed_document_loader_load_from_stdin (XedDocumentLoader *loader);
|
||||
#endif
|
||||
gboolean xed_document_loader_cancel (XedDocumentLoader *loader);
|
||||
|
||||
XedDocument *xed_document_loader_get_document (XedDocumentLoader *loader);
|
||||
|
||||
/* Returns STDIN_URI if loading from stdin */
|
||||
#define STDIN_URI "stdin:"
|
||||
const gchar *xed_document_loader_get_uri (XedDocumentLoader *loader);
|
||||
|
||||
const XedEncoding *xed_document_loader_get_encoding (XedDocumentLoader *loader);
|
||||
|
||||
XedDocumentNewlineType xed_document_loader_get_newline_type (XedDocumentLoader *loader);
|
||||
|
||||
goffset xed_document_loader_get_bytes_read (XedDocumentLoader *loader);
|
||||
|
||||
/* You can get from the info: content_type, time_modified, standard_size, access_can_write
|
||||
and also the metadata*/
|
||||
GFileInfo *xed_document_loader_get_info (XedDocumentLoader *loader);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_DOCUMENT_LOADER_H__ */
|
||||
419
xed/xed-document-output-stream.c
Normal file
419
xed/xed-document-output-stream.c
Normal file
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* xed-document-output-stream.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2010 - Ignacio Casal Quinteiro
|
||||
*
|
||||
* xed is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* xed is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with xed; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gio/gio.h>
|
||||
#include "xed-document-output-stream.h"
|
||||
|
||||
/* NOTE: never use async methods on this stream, the stream is just
|
||||
* a wrapper around GtkTextBuffer api so that we can use GIO Stream
|
||||
* methods, but the undelying code operates on a GtkTextBuffer, so
|
||||
* there is no I/O involved and should be accessed only by the main
|
||||
* thread */
|
||||
|
||||
#define XED_DOCUMENT_OUTPUT_STREAM_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object),\
|
||||
XED_TYPE_DOCUMENT_OUTPUT_STREAM,\
|
||||
XedDocumentOutputStreamPrivate))
|
||||
|
||||
#define MAX_UNICHAR_LEN 6
|
||||
|
||||
struct _XedDocumentOutputStreamPrivate
|
||||
{
|
||||
XedDocument *doc;
|
||||
GtkTextIter pos;
|
||||
|
||||
gchar *buffer;
|
||||
gsize buflen;
|
||||
|
||||
guint is_initialized : 1;
|
||||
guint is_closed : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DOCUMENT
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (XedDocumentOutputStream, xed_document_output_stream, G_TYPE_OUTPUT_STREAM)
|
||||
|
||||
static gssize xed_document_output_stream_write (GOutputStream *stream,
|
||||
const void *buffer,
|
||||
gsize count,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
static gboolean xed_document_output_stream_flush (GOutputStream *stream,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
static gboolean xed_document_output_stream_close (GOutputStream *stream,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
static void
|
||||
xed_document_output_stream_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedDocumentOutputStream *stream = XED_DOCUMENT_OUTPUT_STREAM (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DOCUMENT:
|
||||
stream->priv->doc = XED_DOCUMENT (g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_output_stream_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedDocumentOutputStream *stream = XED_DOCUMENT_OUTPUT_STREAM (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DOCUMENT:
|
||||
g_value_set_object (value, stream->priv->doc);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_output_stream_finalize (GObject *object)
|
||||
{
|
||||
XedDocumentOutputStream *stream = XED_DOCUMENT_OUTPUT_STREAM (object);
|
||||
|
||||
g_free (stream->priv->buffer);
|
||||
|
||||
G_OBJECT_CLASS (xed_document_output_stream_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_output_stream_constructed (GObject *object)
|
||||
{
|
||||
XedDocumentOutputStream *stream = XED_DOCUMENT_OUTPUT_STREAM (object);
|
||||
|
||||
if (!stream->priv->doc)
|
||||
{
|
||||
g_critical ("This should never happen, a problem happened constructing the Document Output Stream!");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Init the undoable action */
|
||||
gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER (stream->priv->doc));
|
||||
/* clear the buffer */
|
||||
gtk_text_buffer_set_text (GTK_TEXT_BUFFER (stream->priv->doc),
|
||||
"", 0);
|
||||
gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (stream->priv->doc),
|
||||
FALSE);
|
||||
|
||||
gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (stream->priv->doc));
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_output_stream_class_init (XedDocumentOutputStreamClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
|
||||
|
||||
object_class->get_property = xed_document_output_stream_get_property;
|
||||
object_class->set_property = xed_document_output_stream_set_property;
|
||||
object_class->finalize = xed_document_output_stream_finalize;
|
||||
object_class->constructed = xed_document_output_stream_constructed;
|
||||
|
||||
stream_class->write_fn = xed_document_output_stream_write;
|
||||
stream_class->flush = xed_document_output_stream_flush;
|
||||
stream_class->close_fn = xed_document_output_stream_close;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_DOCUMENT,
|
||||
g_param_spec_object ("document",
|
||||
"Document",
|
||||
"The document which is written",
|
||||
XED_TYPE_DOCUMENT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (XedDocumentOutputStreamPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_output_stream_init (XedDocumentOutputStream *stream)
|
||||
{
|
||||
stream->priv = XED_DOCUMENT_OUTPUT_STREAM_GET_PRIVATE (stream);
|
||||
|
||||
stream->priv->buffer = NULL;
|
||||
stream->priv->buflen = 0;
|
||||
|
||||
stream->priv->is_initialized = FALSE;
|
||||
stream->priv->is_closed = FALSE;
|
||||
}
|
||||
|
||||
static XedDocumentNewlineType
|
||||
get_newline_type (GtkTextIter *end)
|
||||
{
|
||||
XedDocumentNewlineType res;
|
||||
GtkTextIter copy;
|
||||
gunichar c;
|
||||
|
||||
copy = *end;
|
||||
c = gtk_text_iter_get_char (©);
|
||||
|
||||
if (g_unichar_break_type (c) == G_UNICODE_BREAK_CARRIAGE_RETURN)
|
||||
{
|
||||
if (gtk_text_iter_forward_char (©) &&
|
||||
g_unichar_break_type (gtk_text_iter_get_char (©)) == G_UNICODE_BREAK_LINE_FEED)
|
||||
{
|
||||
res = XED_DOCUMENT_NEWLINE_TYPE_CR_LF;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = XED_DOCUMENT_NEWLINE_TYPE_CR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res = XED_DOCUMENT_NEWLINE_TYPE_LF;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GOutputStream *
|
||||
xed_document_output_stream_new (XedDocument *doc)
|
||||
{
|
||||
return G_OUTPUT_STREAM (g_object_new (XED_TYPE_DOCUMENT_OUTPUT_STREAM,
|
||||
"document", doc, NULL));
|
||||
}
|
||||
|
||||
XedDocumentNewlineType
|
||||
xed_document_output_stream_detect_newline_type (XedDocumentOutputStream *stream)
|
||||
{
|
||||
XedDocumentNewlineType type;
|
||||
GtkTextIter iter;
|
||||
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_OUTPUT_STREAM (stream),
|
||||
XED_DOCUMENT_NEWLINE_TYPE_DEFAULT);
|
||||
|
||||
type = XED_DOCUMENT_NEWLINE_TYPE_DEFAULT;
|
||||
|
||||
gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (stream->priv->doc),
|
||||
&iter);
|
||||
|
||||
if (gtk_text_iter_ends_line (&iter) || gtk_text_iter_forward_to_line_end (&iter))
|
||||
{
|
||||
type = get_newline_type (&iter);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* If the last char is a newline, remove it from the buffer (otherwise
|
||||
GtkTextView shows it as an empty line). See bug #324942. */
|
||||
static void
|
||||
remove_ending_newline (XedDocumentOutputStream *stream)
|
||||
{
|
||||
GtkTextIter end;
|
||||
GtkTextIter start;
|
||||
|
||||
gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (stream->priv->doc), &end);
|
||||
start = end;
|
||||
|
||||
gtk_text_iter_set_line_offset (&start, 0);
|
||||
|
||||
if (gtk_text_iter_ends_line (&start) &&
|
||||
gtk_text_iter_backward_line (&start))
|
||||
{
|
||||
if (!gtk_text_iter_ends_line (&start))
|
||||
{
|
||||
gtk_text_iter_forward_to_line_end (&start);
|
||||
}
|
||||
|
||||
/* Delete the empty line which is from 'start' to 'end' */
|
||||
gtk_text_buffer_delete (GTK_TEXT_BUFFER (stream->priv->doc),
|
||||
&start,
|
||||
&end);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
end_append_text_to_document (XedDocumentOutputStream *stream)
|
||||
{
|
||||
remove_ending_newline (stream);
|
||||
|
||||
gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (stream->priv->doc),
|
||||
FALSE);
|
||||
|
||||
gtk_source_buffer_end_not_undoable_action (GTK_SOURCE_BUFFER (stream->priv->doc));
|
||||
}
|
||||
|
||||
static gssize
|
||||
xed_document_output_stream_write (GOutputStream *stream,
|
||||
const void *buffer,
|
||||
gsize count,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
XedDocumentOutputStream *ostream;
|
||||
gchar *text;
|
||||
gsize len;
|
||||
gboolean freetext = FALSE;
|
||||
const gchar *end;
|
||||
gboolean valid;
|
||||
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
return -1;
|
||||
|
||||
ostream = XED_DOCUMENT_OUTPUT_STREAM (stream);
|
||||
|
||||
if (!ostream->priv->is_initialized)
|
||||
{
|
||||
/* Init the undoable action */
|
||||
gtk_source_buffer_begin_not_undoable_action (GTK_SOURCE_BUFFER (ostream->priv->doc));
|
||||
|
||||
gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (ostream->priv->doc),
|
||||
&ostream->priv->pos);
|
||||
ostream->priv->is_initialized = TRUE;
|
||||
}
|
||||
|
||||
if (ostream->priv->buflen > 0)
|
||||
{
|
||||
len = ostream->priv->buflen + count;
|
||||
text = g_new (gchar , len + 1);
|
||||
memcpy (text, ostream->priv->buffer, ostream->priv->buflen);
|
||||
memcpy (text + ostream->priv->buflen, buffer, count);
|
||||
text[len] = '\0';
|
||||
g_free (ostream->priv->buffer);
|
||||
ostream->priv->buffer = NULL;
|
||||
ostream->priv->buflen = 0;
|
||||
freetext = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
text = (gchar *) buffer;
|
||||
len = count;
|
||||
}
|
||||
|
||||
/* validate */
|
||||
valid = g_utf8_validate (text, len, &end);
|
||||
|
||||
/* Avoid keeping a CRLF across two buffers. */
|
||||
if (valid && len > 1 && end[-1] == '\r')
|
||||
{
|
||||
valid = FALSE;
|
||||
end--;
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
gsize nvalid = end - text;
|
||||
gsize remainder = len - nvalid;
|
||||
gunichar ch;
|
||||
|
||||
if ((remainder < MAX_UNICHAR_LEN) &&
|
||||
((ch = g_utf8_get_char_validated (text + nvalid, remainder)) == (gunichar)-2 ||
|
||||
ch == (gunichar)'\r'))
|
||||
{
|
||||
ostream->priv->buffer = g_strndup (end, remainder);
|
||||
ostream->priv->buflen = remainder;
|
||||
len -= remainder;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: we could escape invalid text and tag it in red
|
||||
* and make the doc readonly.
|
||||
*/
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||
_("Invalid UTF-8 sequence in input"));
|
||||
|
||||
if (freetext)
|
||||
g_free (text);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_text_buffer_insert (GTK_TEXT_BUFFER (ostream->priv->doc),
|
||||
&ostream->priv->pos, text, len);
|
||||
|
||||
if (freetext)
|
||||
g_free (text);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xed_document_output_stream_flush (GOutputStream *stream,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
XedDocumentOutputStream *ostream = XED_DOCUMENT_OUTPUT_STREAM (stream);
|
||||
|
||||
/* Flush deferred data if some. */
|
||||
if (!ostream->priv->is_closed && ostream->priv->is_initialized &&
|
||||
ostream->priv->buflen > 0 &&
|
||||
xed_document_output_stream_write (stream, "", 0, cancellable,
|
||||
error) == -1)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xed_document_output_stream_close (GOutputStream *stream,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
XedDocumentOutputStream *ostream = XED_DOCUMENT_OUTPUT_STREAM (stream);
|
||||
|
||||
if (!ostream->priv->is_closed && ostream->priv->is_initialized)
|
||||
{
|
||||
end_append_text_to_document (ostream);
|
||||
ostream->priv->is_closed = TRUE;
|
||||
}
|
||||
|
||||
if (ostream->priv->buflen > 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||
_("Incomplete UTF-8 sequence in input"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
64
xed/xed-document-output-stream.h
Normal file
64
xed/xed-document-output-stream.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* xed-document-output-stream.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2010 - Ignacio Casal Quinteiro
|
||||
*
|
||||
* xed is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* xed is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with xed; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __XED_DOCUMENT_OUTPUT_STREAM_H__
|
||||
#define __XED_DOCUMENT_OUTPUT_STREAM_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include "xed-document.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_DOCUMENT_OUTPUT_STREAM (xed_document_output_stream_get_type ())
|
||||
#define XED_DOCUMENT_OUTPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_DOCUMENT_OUTPUT_STREAM, XedDocumentOutputStream))
|
||||
#define XED_DOCUMENT_OUTPUT_STREAM_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_DOCUMENT_OUTPUT_STREAM, XedDocumentOutputStream const))
|
||||
#define XED_DOCUMENT_OUTPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_DOCUMENT_OUTPUT_STREAM, XedDocumentOutputStreamClass))
|
||||
#define XED_IS_DOCUMENT_OUTPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_DOCUMENT_OUTPUT_STREAM))
|
||||
#define XED_IS_DOCUMENT_OUTPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_DOCUMENT_OUTPUT_STREAM))
|
||||
#define XED_DOCUMENT_OUTPUT_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_DOCUMENT_OUTPUT_STREAM, XedDocumentOutputStreamClass))
|
||||
|
||||
typedef struct _XedDocumentOutputStream XedDocumentOutputStream;
|
||||
typedef struct _XedDocumentOutputStreamClass XedDocumentOutputStreamClass;
|
||||
typedef struct _XedDocumentOutputStreamPrivate XedDocumentOutputStreamPrivate;
|
||||
|
||||
struct _XedDocumentOutputStream
|
||||
{
|
||||
GOutputStream parent;
|
||||
|
||||
XedDocumentOutputStreamPrivate *priv;
|
||||
};
|
||||
|
||||
struct _XedDocumentOutputStreamClass
|
||||
{
|
||||
GOutputStreamClass parent_class;
|
||||
};
|
||||
|
||||
GType xed_document_output_stream_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GOutputStream *xed_document_output_stream_new (XedDocument *doc);
|
||||
|
||||
XedDocumentNewlineType xed_document_output_stream_detect_newline_type (XedDocumentOutputStream *stream);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_DOCUMENT_OUTPUT_STREAM_H__ */
|
||||
359
xed/xed-document-saver.c
Normal file
359
xed/xed-document-saver.c
Normal file
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* xed-document-saver.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005-2006 - Paolo Borelli and Paolo Maggi
|
||||
* Copyright (C) 2007 - Paolo Borelli, Paolo Maggi, Steve Frécinaux
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005-2006. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "xed-document-saver.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-prefs-manager.h"
|
||||
#include "xed-marshal.h"
|
||||
#include "xed-utils.h"
|
||||
#include "xed-enum-types.h"
|
||||
#include "xed-gio-document-saver.h"
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE(XedDocumentSaver, xed_document_saver, G_TYPE_OBJECT)
|
||||
|
||||
/* Signals */
|
||||
|
||||
enum {
|
||||
SAVING,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
/* Properties */
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DOCUMENT,
|
||||
PROP_URI,
|
||||
PROP_ENCODING,
|
||||
PROP_NEWLINE_TYPE,
|
||||
PROP_FLAGS
|
||||
};
|
||||
|
||||
static void
|
||||
xed_document_saver_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedDocumentSaver *saver = XED_DOCUMENT_SAVER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DOCUMENT:
|
||||
g_return_if_fail (saver->document == NULL);
|
||||
saver->document = g_value_get_object (value);
|
||||
break;
|
||||
case PROP_URI:
|
||||
g_return_if_fail (saver->uri == NULL);
|
||||
saver->uri = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_ENCODING:
|
||||
g_return_if_fail (saver->encoding == NULL);
|
||||
saver->encoding = g_value_get_boxed (value);
|
||||
break;
|
||||
case PROP_NEWLINE_TYPE:
|
||||
saver->newline_type = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_FLAGS:
|
||||
saver->flags = g_value_get_flags (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_saver_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedDocumentSaver *saver = XED_DOCUMENT_SAVER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DOCUMENT:
|
||||
g_value_set_object (value, saver->document);
|
||||
break;
|
||||
case PROP_URI:
|
||||
g_value_set_string (value, saver->uri);
|
||||
break;
|
||||
case PROP_ENCODING:
|
||||
g_value_set_boxed (value, saver->encoding);
|
||||
break;
|
||||
case PROP_NEWLINE_TYPE:
|
||||
g_value_set_enum (value, saver->newline_type);
|
||||
break;
|
||||
case PROP_FLAGS:
|
||||
g_value_set_flags (value, saver->flags);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_saver_finalize (GObject *object)
|
||||
{
|
||||
XedDocumentSaver *saver = XED_DOCUMENT_SAVER (object);
|
||||
|
||||
g_free (saver->uri);
|
||||
|
||||
G_OBJECT_CLASS (xed_document_saver_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_saver_dispose (GObject *object)
|
||||
{
|
||||
XedDocumentSaver *saver = XED_DOCUMENT_SAVER (object);
|
||||
|
||||
if (saver->info != NULL)
|
||||
{
|
||||
g_object_unref (saver->info);
|
||||
saver->info = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (xed_document_saver_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_saver_class_init (XedDocumentSaverClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = xed_document_saver_finalize;
|
||||
object_class->dispose = xed_document_saver_dispose;
|
||||
object_class->set_property = xed_document_saver_set_property;
|
||||
object_class->get_property = xed_document_saver_get_property;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_DOCUMENT,
|
||||
g_param_spec_object ("document",
|
||||
"Document",
|
||||
"The XedDocument this XedDocumentSaver is associated with",
|
||||
XED_TYPE_DOCUMENT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_URI,
|
||||
g_param_spec_string ("uri",
|
||||
"URI",
|
||||
"The URI this XedDocumentSaver saves the document to",
|
||||
"",
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_ENCODING,
|
||||
g_param_spec_boxed ("encoding",
|
||||
"URI",
|
||||
"The encoding of the saved file",
|
||||
XED_TYPE_ENCODING,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_NEWLINE_TYPE,
|
||||
g_param_spec_enum ("newline-type",
|
||||
"Newline type",
|
||||
"The accepted types of line ending",
|
||||
XED_TYPE_DOCUMENT_NEWLINE_TYPE,
|
||||
XED_DOCUMENT_NEWLINE_TYPE_LF,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_NAME |
|
||||
G_PARAM_STATIC_BLURB |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_FLAGS,
|
||||
g_param_spec_flags ("flags",
|
||||
"Flags",
|
||||
"The flags for the saving operation",
|
||||
XED_TYPE_DOCUMENT_SAVE_FLAGS,
|
||||
0,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
signals[SAVING] =
|
||||
g_signal_new ("saving",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (XedDocumentSaverClass, saving),
|
||||
NULL, NULL,
|
||||
xed_marshal_VOID__BOOLEAN_POINTER,
|
||||
G_TYPE_NONE,
|
||||
2,
|
||||
G_TYPE_BOOLEAN,
|
||||
G_TYPE_POINTER);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_document_saver_init (XedDocumentSaver *saver)
|
||||
{
|
||||
saver->used = FALSE;
|
||||
}
|
||||
|
||||
XedDocumentSaver *
|
||||
xed_document_saver_new (XedDocument *doc,
|
||||
const gchar *uri,
|
||||
const XedEncoding *encoding,
|
||||
XedDocumentNewlineType newline_type,
|
||||
XedDocumentSaveFlags flags)
|
||||
{
|
||||
XedDocumentSaver *saver;
|
||||
GType saver_type;
|
||||
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT (doc), NULL);
|
||||
|
||||
saver_type = XED_TYPE_GIO_DOCUMENT_SAVER;
|
||||
|
||||
if (encoding == NULL)
|
||||
encoding = xed_encoding_get_utf8 ();
|
||||
|
||||
saver = XED_DOCUMENT_SAVER (g_object_new (saver_type,
|
||||
"document", doc,
|
||||
"uri", uri,
|
||||
"encoding", encoding,
|
||||
"newline_type", newline_type,
|
||||
"flags", flags,
|
||||
NULL));
|
||||
|
||||
return saver;
|
||||
}
|
||||
|
||||
void
|
||||
xed_document_saver_saving (XedDocumentSaver *saver,
|
||||
gboolean completed,
|
||||
GError *error)
|
||||
{
|
||||
/* the object will be unrefed in the callback of the saving
|
||||
* signal, so we need to prevent finalization.
|
||||
*/
|
||||
if (completed)
|
||||
{
|
||||
g_object_ref (saver);
|
||||
}
|
||||
|
||||
g_signal_emit (saver, signals[SAVING], 0, completed, error);
|
||||
|
||||
if (completed)
|
||||
{
|
||||
if (error == NULL)
|
||||
xed_debug_message (DEBUG_SAVER, "save completed");
|
||||
else
|
||||
xed_debug_message (DEBUG_SAVER, "save failed");
|
||||
|
||||
g_object_unref (saver);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xed_document_saver_save (XedDocumentSaver *saver,
|
||||
GTimeVal *old_mtime)
|
||||
{
|
||||
xed_debug (DEBUG_SAVER);
|
||||
|
||||
g_return_if_fail (XED_IS_DOCUMENT_SAVER (saver));
|
||||
g_return_if_fail (saver->uri != NULL && strlen (saver->uri) > 0);
|
||||
|
||||
g_return_if_fail (saver->used == FALSE);
|
||||
saver->used = TRUE;
|
||||
|
||||
// CHECK:
|
||||
// - sanity check a max len for the uri?
|
||||
// report async (in an idle handler) or sync (bool ret)
|
||||
// async is extra work here, sync is special casing in the caller
|
||||
|
||||
/* never keep backup of autosaves */
|
||||
if ((saver->flags & XED_DOCUMENT_SAVE_PRESERVE_BACKUP) != 0)
|
||||
saver->keep_backup = FALSE;
|
||||
else
|
||||
saver->keep_backup = xed_prefs_manager_get_create_backup_copy ();
|
||||
|
||||
XED_DOCUMENT_SAVER_GET_CLASS (saver)->save (saver, old_mtime);
|
||||
}
|
||||
|
||||
XedDocument *
|
||||
xed_document_saver_get_document (XedDocumentSaver *saver)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_SAVER (saver), NULL);
|
||||
|
||||
return saver->document;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_document_saver_get_uri (XedDocumentSaver *saver)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_SAVER (saver), NULL);
|
||||
|
||||
return saver->uri;
|
||||
}
|
||||
|
||||
/* Returns 0 if file size is unknown */
|
||||
goffset
|
||||
xed_document_saver_get_file_size (XedDocumentSaver *saver)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_SAVER (saver), 0);
|
||||
|
||||
return XED_DOCUMENT_SAVER_GET_CLASS (saver)->get_file_size (saver);
|
||||
}
|
||||
|
||||
goffset
|
||||
xed_document_saver_get_bytes_written (XedDocumentSaver *saver)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_SAVER (saver), 0);
|
||||
|
||||
return XED_DOCUMENT_SAVER_GET_CLASS (saver)->get_bytes_written (saver);
|
||||
}
|
||||
|
||||
GFileInfo *
|
||||
xed_document_saver_get_info (XedDocumentSaver *saver)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_DOCUMENT_SAVER (saver), NULL);
|
||||
|
||||
return saver->info;
|
||||
}
|
||||
133
xed/xed-document-saver.h
Normal file
133
xed/xed-document-saver.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* xed-document-saver.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
* Copyrhing (C) 2007 - Paolo Maggi, Steve Frécinaux
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_DOCUMENT_SAVER_H__
|
||||
#define __XED_DOCUMENT_SAVER_H__
|
||||
|
||||
#include <xed/xed-document.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_DOCUMENT_SAVER (xed_document_saver_get_type())
|
||||
#define XED_DOCUMENT_SAVER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_DOCUMENT_SAVER, XedDocumentSaver))
|
||||
#define XED_DOCUMENT_SAVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_DOCUMENT_SAVER, XedDocumentSaverClass))
|
||||
#define XED_IS_DOCUMENT_SAVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_DOCUMENT_SAVER))
|
||||
#define XED_IS_DOCUMENT_SAVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_DOCUMENT_SAVER))
|
||||
#define XED_DOCUMENT_SAVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_DOCUMENT_SAVER, XedDocumentSaverClass))
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedDocumentSaver XedDocumentSaver;
|
||||
|
||||
struct _XedDocumentSaver
|
||||
{
|
||||
GObject object;
|
||||
|
||||
/*< private >*/
|
||||
GFileInfo *info;
|
||||
XedDocument *document;
|
||||
gboolean used;
|
||||
|
||||
gchar *uri;
|
||||
const XedEncoding *encoding;
|
||||
XedDocumentNewlineType newline_type;
|
||||
|
||||
XedDocumentSaveFlags flags;
|
||||
|
||||
gboolean keep_backup;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedDocumentSaverClass XedDocumentSaverClass;
|
||||
|
||||
struct _XedDocumentSaverClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* saving) (XedDocumentSaver *saver,
|
||||
gboolean completed,
|
||||
const GError *error);
|
||||
|
||||
/* VTable */
|
||||
void (* save) (XedDocumentSaver *saver,
|
||||
GTimeVal *old_mtime);
|
||||
goffset (* get_file_size) (XedDocumentSaver *saver);
|
||||
goffset (* get_bytes_written) (XedDocumentSaver *saver);
|
||||
};
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_document_saver_get_type (void) G_GNUC_CONST;
|
||||
|
||||
/* If enconding == NULL, the encoding will be autodetected */
|
||||
XedDocumentSaver *xed_document_saver_new (XedDocument *doc,
|
||||
const gchar *uri,
|
||||
const XedEncoding *encoding,
|
||||
XedDocumentNewlineType newline_type,
|
||||
XedDocumentSaveFlags flags);
|
||||
|
||||
void xed_document_saver_saving (XedDocumentSaver *saver,
|
||||
gboolean completed,
|
||||
GError *error);
|
||||
void xed_document_saver_save (XedDocumentSaver *saver,
|
||||
GTimeVal *old_mtime);
|
||||
|
||||
#if 0
|
||||
void xed_document_saver_cancel (XedDocumentSaver *saver);
|
||||
#endif
|
||||
|
||||
XedDocument *xed_document_saver_get_document (XedDocumentSaver *saver);
|
||||
|
||||
const gchar *xed_document_saver_get_uri (XedDocumentSaver *saver);
|
||||
|
||||
/* If backup_uri is NULL no backup will be made */
|
||||
const gchar *xed_document_saver_get_backup_uri (XedDocumentSaver *saver);
|
||||
void *xed_document_saver_set_backup_uri (XedDocumentSaver *saver,
|
||||
const gchar *backup_uri);
|
||||
|
||||
/* Returns 0 if file size is unknown */
|
||||
goffset xed_document_saver_get_file_size (XedDocumentSaver *saver);
|
||||
|
||||
goffset xed_document_saver_get_bytes_written (XedDocumentSaver *saver);
|
||||
|
||||
GFileInfo *xed_document_saver_get_info (XedDocumentSaver *saver);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_DOCUMENT_SAVER_H__ */
|
||||
2901
xed/xed-document.c
Normal file
2901
xed/xed-document.c
Normal file
File diff suppressed because it is too large
Load Diff
333
xed/xed-document.h
Normal file
333
xed/xed-document.h
Normal file
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* xed-document.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
|
||||
* Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 1998-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_DOCUMENT_H__
|
||||
#define __XED_DOCUMENT_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gtksourceview/gtksourcebuffer.h>
|
||||
|
||||
#include <xed/xed-encodings.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_DOCUMENT (xed_document_get_type())
|
||||
#define XED_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_DOCUMENT, XedDocument))
|
||||
#define XED_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_DOCUMENT, XedDocumentClass))
|
||||
#define XED_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_DOCUMENT))
|
||||
#define XED_IS_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_DOCUMENT))
|
||||
#define XED_DOCUMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_DOCUMENT, XedDocumentClass))
|
||||
|
||||
#define XED_METADATA_ATTRIBUTE_POSITION "metadata::xed-position"
|
||||
#define XED_METADATA_ATTRIBUTE_ENCODING "metadata::xed-encoding"
|
||||
#define XED_METADATA_ATTRIBUTE_LANGUAGE "metadata::xed-language"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XED_DOCUMENT_NEWLINE_TYPE_LF,
|
||||
XED_DOCUMENT_NEWLINE_TYPE_CR,
|
||||
XED_DOCUMENT_NEWLINE_TYPE_CR_LF
|
||||
} XedDocumentNewlineType;
|
||||
|
||||
#define XED_DOCUMENT_NEWLINE_TYPE_DEFAULT XED_DOCUMENT_NEWLINE_TYPE_LF
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XED_SEARCH_DONT_SET_FLAGS = 1 << 0,
|
||||
XED_SEARCH_ENTIRE_WORD = 1 << 1,
|
||||
XED_SEARCH_CASE_SENSITIVE = 1 << 2,
|
||||
XED_SEARCH_PARSE_ESCAPES = 1 << 3
|
||||
|
||||
} XedSearchFlags;
|
||||
|
||||
/**
|
||||
* XedDocumentSaveFlags:
|
||||
* @XED_DOCUMENT_SAVE_IGNORE_MTIME: save file despite external modifications.
|
||||
* @XED_DOCUMENT_SAVE_IGNORE_BACKUP: write the file directly without attempting to backup.
|
||||
* @XED_DOCUMENT_SAVE_PRESERVE_BACKUP: preserve previous backup file, needed to support autosaving.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
XED_DOCUMENT_SAVE_IGNORE_MTIME = 1 << 0,
|
||||
XED_DOCUMENT_SAVE_IGNORE_BACKUP = 1 << 1,
|
||||
XED_DOCUMENT_SAVE_PRESERVE_BACKUP = 1 << 2
|
||||
} XedDocumentSaveFlags;
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedDocumentPrivate XedDocumentPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedDocument XedDocument;
|
||||
|
||||
struct _XedDocument
|
||||
{
|
||||
GtkSourceBuffer buffer;
|
||||
|
||||
/*< private > */
|
||||
XedDocumentPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedDocumentClass XedDocumentClass;
|
||||
|
||||
struct _XedDocumentClass
|
||||
{
|
||||
GtkSourceBufferClass parent_class;
|
||||
|
||||
/* Signals */ // CHECK: ancora da rivedere
|
||||
|
||||
void (* cursor_moved) (XedDocument *document);
|
||||
|
||||
/* Document load */
|
||||
void (* load) (XedDocument *document,
|
||||
const gchar *uri,
|
||||
const XedEncoding *encoding,
|
||||
gint line_pos,
|
||||
gboolean create);
|
||||
|
||||
void (* loading) (XedDocument *document,
|
||||
goffset size,
|
||||
goffset total_size);
|
||||
|
||||
void (* loaded) (XedDocument *document,
|
||||
const GError *error);
|
||||
|
||||
/* Document save */
|
||||
void (* save) (XedDocument *document,
|
||||
const gchar *uri,
|
||||
const XedEncoding *encoding,
|
||||
XedDocumentSaveFlags flags);
|
||||
|
||||
void (* saving) (XedDocument *document,
|
||||
goffset size,
|
||||
goffset total_size);
|
||||
|
||||
void (* saved) (XedDocument *document,
|
||||
const GError *error);
|
||||
|
||||
void (* search_highlight_updated)
|
||||
(XedDocument *document,
|
||||
GtkTextIter *start,
|
||||
GtkTextIter *end);
|
||||
};
|
||||
|
||||
|
||||
#define XED_DOCUMENT_ERROR xed_document_error_quark ()
|
||||
|
||||
enum
|
||||
{
|
||||
XED_DOCUMENT_ERROR_EXTERNALLY_MODIFIED,
|
||||
XED_DOCUMENT_ERROR_CANT_CREATE_BACKUP,
|
||||
XED_DOCUMENT_ERROR_TOO_BIG,
|
||||
XED_DOCUMENT_ERROR_ENCODING_AUTO_DETECTION_FAILED,
|
||||
XED_DOCUMENT_ERROR_CONVERSION_FALLBACK,
|
||||
XED_DOCUMENT_NUM_ERRORS
|
||||
};
|
||||
|
||||
GQuark xed_document_error_quark (void);
|
||||
|
||||
GType xed_document_get_type (void) G_GNUC_CONST;
|
||||
|
||||
XedDocument *xed_document_new (void);
|
||||
|
||||
GFile *xed_document_get_location (XedDocument *doc);
|
||||
|
||||
gchar *xed_document_get_uri (XedDocument *doc);
|
||||
void xed_document_set_uri (XedDocument *doc,
|
||||
const gchar *uri);
|
||||
|
||||
gchar *xed_document_get_uri_for_display
|
||||
(XedDocument *doc);
|
||||
gchar *xed_document_get_short_name_for_display
|
||||
(XedDocument *doc);
|
||||
|
||||
void xed_document_set_short_name_for_display
|
||||
(XedDocument *doc,
|
||||
const gchar *name);
|
||||
|
||||
gchar *xed_document_get_content_type
|
||||
(XedDocument *doc);
|
||||
|
||||
void xed_document_set_content_type
|
||||
(XedDocument *doc,
|
||||
const gchar *content_type);
|
||||
|
||||
gchar *xed_document_get_mime_type (XedDocument *doc);
|
||||
|
||||
gboolean xed_document_get_readonly (XedDocument *doc);
|
||||
|
||||
void xed_document_load (XedDocument *doc,
|
||||
const gchar *uri,
|
||||
const XedEncoding *encoding,
|
||||
gint line_pos,
|
||||
gboolean create);
|
||||
|
||||
gboolean xed_document_insert_file (XedDocument *doc,
|
||||
GtkTextIter *iter,
|
||||
const gchar *uri,
|
||||
const XedEncoding *encoding);
|
||||
|
||||
gboolean xed_document_load_cancel (XedDocument *doc);
|
||||
|
||||
void xed_document_save (XedDocument *doc,
|
||||
XedDocumentSaveFlags flags);
|
||||
|
||||
void xed_document_save_as (XedDocument *doc,
|
||||
const gchar *uri,
|
||||
const XedEncoding *encoding,
|
||||
XedDocumentSaveFlags flags);
|
||||
|
||||
gboolean xed_document_is_untouched (XedDocument *doc);
|
||||
gboolean xed_document_is_untitled (XedDocument *doc);
|
||||
|
||||
gboolean xed_document_is_local (XedDocument *doc);
|
||||
|
||||
gboolean xed_document_get_deleted (XedDocument *doc);
|
||||
|
||||
gboolean xed_document_goto_line (XedDocument *doc,
|
||||
gint line);
|
||||
|
||||
gboolean xed_document_goto_line_offset(XedDocument *doc,
|
||||
gint line,
|
||||
gint line_offset);
|
||||
|
||||
void xed_document_set_search_text (XedDocument *doc,
|
||||
const gchar *text,
|
||||
guint flags);
|
||||
|
||||
gchar *xed_document_get_search_text (XedDocument *doc,
|
||||
guint *flags);
|
||||
|
||||
gboolean xed_document_get_can_search_again
|
||||
(XedDocument *doc);
|
||||
|
||||
gboolean xed_document_search_forward (XedDocument *doc,
|
||||
const GtkTextIter *start,
|
||||
const GtkTextIter *end,
|
||||
GtkTextIter *match_start,
|
||||
GtkTextIter *match_end);
|
||||
|
||||
gboolean xed_document_search_backward (XedDocument *doc,
|
||||
const GtkTextIter *start,
|
||||
const GtkTextIter *end,
|
||||
GtkTextIter *match_start,
|
||||
GtkTextIter *match_end);
|
||||
|
||||
gint xed_document_replace_all (XedDocument *doc,
|
||||
const gchar *find,
|
||||
const gchar *replace,
|
||||
guint flags);
|
||||
|
||||
void xed_document_set_language (XedDocument *doc,
|
||||
GtkSourceLanguage *lang);
|
||||
GtkSourceLanguage
|
||||
*xed_document_get_language (XedDocument *doc);
|
||||
|
||||
const XedEncoding
|
||||
*xed_document_get_encoding (XedDocument *doc);
|
||||
|
||||
void xed_document_set_enable_search_highlighting
|
||||
(XedDocument *doc,
|
||||
gboolean enable);
|
||||
|
||||
gboolean xed_document_get_enable_search_highlighting
|
||||
(XedDocument *doc);
|
||||
|
||||
void xed_document_set_newline_type (XedDocument *doc,
|
||||
XedDocumentNewlineType newline_type);
|
||||
|
||||
XedDocumentNewlineType
|
||||
xed_document_get_newline_type (XedDocument *doc);
|
||||
|
||||
gchar *xed_document_get_metadata (XedDocument *doc,
|
||||
const gchar *key);
|
||||
|
||||
void xed_document_set_metadata (XedDocument *doc,
|
||||
const gchar *first_key,
|
||||
...);
|
||||
|
||||
/*
|
||||
* Non exported functions
|
||||
*/
|
||||
void _xed_document_set_readonly (XedDocument *doc,
|
||||
gboolean readonly);
|
||||
|
||||
glong _xed_document_get_seconds_since_last_save_or_load
|
||||
(XedDocument *doc);
|
||||
|
||||
/* Note: this is a sync stat: use only on local files */
|
||||
gboolean _xed_document_check_externally_modified
|
||||
(XedDocument *doc);
|
||||
|
||||
void _xed_document_search_region (XedDocument *doc,
|
||||
const GtkTextIter *start,
|
||||
const GtkTextIter *end);
|
||||
|
||||
/* Search macros */
|
||||
#define XED_SEARCH_IS_DONT_SET_FLAGS(sflags) ((sflags & XED_SEARCH_DONT_SET_FLAGS) != 0)
|
||||
#define XED_SEARCH_SET_DONT_SET_FLAGS(sflags,state) ((state == TRUE) ? \
|
||||
(sflags |= XED_SEARCH_DONT_SET_FLAGS) : (sflags &= ~XED_SEARCH_DONT_SET_FLAGS))
|
||||
|
||||
#define XED_SEARCH_IS_ENTIRE_WORD(sflags) ((sflags & XED_SEARCH_ENTIRE_WORD) != 0)
|
||||
#define XED_SEARCH_SET_ENTIRE_WORD(sflags,state) ((state == TRUE) ? \
|
||||
(sflags |= XED_SEARCH_ENTIRE_WORD) : (sflags &= ~XED_SEARCH_ENTIRE_WORD))
|
||||
|
||||
#define XED_SEARCH_IS_CASE_SENSITIVE(sflags) ((sflags & XED_SEARCH_CASE_SENSITIVE) != 0)
|
||||
#define XED_SEARCH_SET_CASE_SENSITIVE(sflags,state) ((state == TRUE) ? \
|
||||
(sflags |= XED_SEARCH_CASE_SENSITIVE) : (sflags &= ~XED_SEARCH_CASE_SENSITIVE))
|
||||
|
||||
#define XED_SEARCH_IS_PARSE_ESCAPES(sflags) ((sflags & XED_SEARCH_PARSE_ESCAPES) != 0)
|
||||
#define XED_SEARCH_SET_PARSE_ESCAPES(sflags,state) ((state == TRUE) ? \
|
||||
(sflags |= XED_SEARCH_PARSE_ESCAPES) : (sflags &= ~XED_SEARCH_PARSE_ESCAPES))
|
||||
|
||||
typedef GMountOperation *(*XedMountOperationFactory)(XedDocument *doc,
|
||||
gpointer userdata);
|
||||
|
||||
void _xed_document_set_mount_operation_factory
|
||||
(XedDocument *doc,
|
||||
XedMountOperationFactory callback,
|
||||
gpointer userdata);
|
||||
GMountOperation
|
||||
*_xed_document_create_mount_operation
|
||||
(XedDocument *doc);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_DOCUMENT_H__ */
|
||||
844
xed/xed-documents-panel.c
Normal file
844
xed/xed-documents-panel.c
Normal file
@@ -0,0 +1,844 @@
|
||||
/*
|
||||
* xed-documents-panel.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "xed-documents-panel.h"
|
||||
#include "xed-utils.h"
|
||||
#include "xed-notebook.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#define XED_DOCUMENTS_PANEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
|
||||
XED_TYPE_DOCUMENTS_PANEL, \
|
||||
XedDocumentsPanelPrivate))
|
||||
|
||||
struct _XedDocumentsPanelPrivate
|
||||
{
|
||||
XedWindow *window;
|
||||
|
||||
GtkWidget *treeview;
|
||||
GtkTreeModel *model;
|
||||
|
||||
guint adding_tab : 1;
|
||||
guint is_reodering : 1;
|
||||
};
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
G_DEFINE_TYPE(XedDocumentsPanel, xed_documents_panel, GTK_TYPE_BOX)
|
||||
#else
|
||||
G_DEFINE_TYPE(XedDocumentsPanel, xed_documents_panel, GTK_TYPE_VBOX)
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_WINDOW
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PIXBUF_COLUMN,
|
||||
NAME_COLUMN,
|
||||
TAB_COLUMN,
|
||||
N_COLUMNS
|
||||
};
|
||||
|
||||
#define MAX_DOC_NAME_LENGTH 60
|
||||
|
||||
static gchar *
|
||||
tab_get_name (XedTab *tab)
|
||||
{
|
||||
XedDocument *doc;
|
||||
gchar *name;
|
||||
gchar *docname;
|
||||
gchar *tab_name;
|
||||
|
||||
g_return_val_if_fail (XED_IS_TAB (tab), NULL);
|
||||
|
||||
doc = xed_tab_get_document (tab);
|
||||
|
||||
name = xed_document_get_short_name_for_display (doc);
|
||||
|
||||
/* Truncate the name so it doesn't get insanely wide. */
|
||||
docname = xed_utils_str_middle_truncate (name, MAX_DOC_NAME_LENGTH);
|
||||
|
||||
if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)))
|
||||
{
|
||||
if (xed_document_get_readonly (doc))
|
||||
{
|
||||
tab_name = g_markup_printf_escaped ("<i>%s</i> [<i>%s</i>]",
|
||||
docname,
|
||||
_("Read-Only"));
|
||||
}
|
||||
else
|
||||
{
|
||||
tab_name = g_markup_printf_escaped ("<i>%s</i>",
|
||||
docname);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (xed_document_get_readonly (doc))
|
||||
{
|
||||
tab_name = g_markup_printf_escaped ("%s [<i>%s</i>]",
|
||||
docname,
|
||||
_("Read-Only"));
|
||||
}
|
||||
else
|
||||
{
|
||||
tab_name = g_markup_escape_text (docname, -1);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (docname);
|
||||
g_free (name);
|
||||
|
||||
return tab_name;
|
||||
}
|
||||
|
||||
static void
|
||||
get_iter_from_tab (XedDocumentsPanel *panel, XedTab *tab, GtkTreeIter *iter)
|
||||
{
|
||||
gint num;
|
||||
GtkWidget *nb;
|
||||
GtkTreePath *path;
|
||||
|
||||
nb = _xed_window_get_notebook (panel->priv->window);
|
||||
num = gtk_notebook_page_num (GTK_NOTEBOOK (nb),
|
||||
GTK_WIDGET (tab));
|
||||
|
||||
path = gtk_tree_path_new_from_indices (num, -1);
|
||||
gtk_tree_model_get_iter (panel->priv->model,
|
||||
iter,
|
||||
path);
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
window_active_tab_changed (XedWindow *window,
|
||||
XedTab *tab,
|
||||
XedDocumentsPanel *panel)
|
||||
{
|
||||
g_return_if_fail (tab != NULL);
|
||||
|
||||
if (!_xed_window_is_removing_tabs (window))
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
get_iter_from_tab (panel, tab, &iter);
|
||||
|
||||
if (gtk_list_store_iter_is_valid (GTK_LIST_STORE (panel->priv->model),
|
||||
&iter))
|
||||
{
|
||||
selection = gtk_tree_view_get_selection (
|
||||
GTK_TREE_VIEW (panel->priv->treeview));
|
||||
|
||||
gtk_tree_selection_select_iter (selection, &iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
refresh_list (XedDocumentsPanel *panel)
|
||||
{
|
||||
/* TODO: refresh the list only if the panel is visible */
|
||||
|
||||
GList *tabs;
|
||||
GList *l;
|
||||
GtkWidget *nb;
|
||||
GtkListStore *list_store;
|
||||
XedTab *active_tab;
|
||||
|
||||
/* g_debug ("refresh_list"); */
|
||||
|
||||
list_store = GTK_LIST_STORE (panel->priv->model);
|
||||
|
||||
gtk_list_store_clear (list_store);
|
||||
|
||||
active_tab = xed_window_get_active_tab (panel->priv->window);
|
||||
|
||||
nb = _xed_window_get_notebook (panel->priv->window);
|
||||
|
||||
tabs = gtk_container_get_children (GTK_CONTAINER (nb));
|
||||
l = tabs;
|
||||
|
||||
panel->priv->adding_tab = TRUE;
|
||||
|
||||
while (l != NULL)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
gchar *name;
|
||||
GtkTreeIter iter;
|
||||
|
||||
name = tab_get_name (XED_TAB (l->data));
|
||||
pixbuf = _xed_tab_get_icon (XED_TAB (l->data));
|
||||
|
||||
/* Add a new row to the model */
|
||||
gtk_list_store_append (list_store, &iter);
|
||||
gtk_list_store_set (list_store,
|
||||
&iter,
|
||||
PIXBUF_COLUMN, pixbuf,
|
||||
NAME_COLUMN, name,
|
||||
TAB_COLUMN, l->data,
|
||||
-1);
|
||||
|
||||
g_free (name);
|
||||
if (pixbuf != NULL)
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
if (l->data == active_tab)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
selection = gtk_tree_view_get_selection (
|
||||
GTK_TREE_VIEW (panel->priv->treeview));
|
||||
|
||||
gtk_tree_selection_select_iter (selection, &iter);
|
||||
}
|
||||
|
||||
l = g_list_next (l);
|
||||
}
|
||||
|
||||
panel->priv->adding_tab = FALSE;
|
||||
|
||||
g_list_free (tabs);
|
||||
}
|
||||
|
||||
static void
|
||||
sync_name_and_icon (XedTab *tab,
|
||||
GParamSpec *pspec,
|
||||
XedDocumentsPanel *panel)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
gchar *name;
|
||||
GtkTreeIter iter;
|
||||
|
||||
get_iter_from_tab (panel, tab, &iter);
|
||||
|
||||
name = tab_get_name (tab);
|
||||
pixbuf = _xed_tab_get_icon (tab);
|
||||
|
||||
gtk_list_store_set (GTK_LIST_STORE (panel->priv->model),
|
||||
&iter,
|
||||
PIXBUF_COLUMN, pixbuf,
|
||||
NAME_COLUMN, name,
|
||||
TAB_COLUMN, tab,
|
||||
-1);
|
||||
|
||||
g_free (name);
|
||||
if (pixbuf != NULL)
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
window_tab_removed (XedWindow *window,
|
||||
XedTab *tab,
|
||||
XedDocumentsPanel *panel)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (tab,
|
||||
G_CALLBACK (sync_name_and_icon),
|
||||
panel);
|
||||
|
||||
if (_xed_window_is_removing_tabs (window))
|
||||
gtk_list_store_clear (GTK_LIST_STORE (panel->priv->model));
|
||||
else
|
||||
refresh_list (panel);
|
||||
}
|
||||
|
||||
static void
|
||||
window_tab_added (XedWindow *window,
|
||||
XedTab *tab,
|
||||
XedDocumentsPanel *panel)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkTreeIter sibling;
|
||||
GdkPixbuf *pixbuf;
|
||||
gchar *name;
|
||||
|
||||
g_signal_connect (tab,
|
||||
"notify::name",
|
||||
G_CALLBACK (sync_name_and_icon),
|
||||
panel);
|
||||
|
||||
g_signal_connect (tab,
|
||||
"notify::state",
|
||||
G_CALLBACK (sync_name_and_icon),
|
||||
panel);
|
||||
|
||||
get_iter_from_tab (panel, tab, &sibling);
|
||||
|
||||
panel->priv->adding_tab = TRUE;
|
||||
|
||||
if (gtk_list_store_iter_is_valid (GTK_LIST_STORE (panel->priv->model),
|
||||
&sibling))
|
||||
{
|
||||
gtk_list_store_insert_after (GTK_LIST_STORE (panel->priv->model),
|
||||
&iter,
|
||||
&sibling);
|
||||
}
|
||||
else
|
||||
{
|
||||
XedTab *active_tab;
|
||||
|
||||
gtk_list_store_append (GTK_LIST_STORE (panel->priv->model),
|
||||
&iter);
|
||||
|
||||
active_tab = xed_window_get_active_tab (panel->priv->window);
|
||||
|
||||
if (tab == active_tab)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
selection = gtk_tree_view_get_selection (
|
||||
GTK_TREE_VIEW (panel->priv->treeview));
|
||||
|
||||
gtk_tree_selection_select_iter (selection, &iter);
|
||||
}
|
||||
}
|
||||
|
||||
name = tab_get_name (tab);
|
||||
pixbuf = _xed_tab_get_icon (tab);
|
||||
|
||||
gtk_list_store_set (GTK_LIST_STORE (panel->priv->model),
|
||||
&iter,
|
||||
PIXBUF_COLUMN, pixbuf,
|
||||
NAME_COLUMN, name,
|
||||
TAB_COLUMN, tab,
|
||||
-1);
|
||||
|
||||
g_free (name);
|
||||
if (pixbuf != NULL)
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
panel->priv->adding_tab = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
window_tabs_reordered (XedWindow *window,
|
||||
XedDocumentsPanel *panel)
|
||||
{
|
||||
if (panel->priv->is_reodering)
|
||||
return;
|
||||
|
||||
refresh_list (panel);
|
||||
}
|
||||
|
||||
static void
|
||||
set_window (XedDocumentsPanel *panel,
|
||||
XedWindow *window)
|
||||
{
|
||||
g_return_if_fail (panel->priv->window == NULL);
|
||||
g_return_if_fail (XED_IS_WINDOW (window));
|
||||
|
||||
panel->priv->window = g_object_ref (window);
|
||||
|
||||
g_signal_connect (window,
|
||||
"tab_added",
|
||||
G_CALLBACK (window_tab_added),
|
||||
panel);
|
||||
g_signal_connect (window,
|
||||
"tab_removed",
|
||||
G_CALLBACK (window_tab_removed),
|
||||
panel);
|
||||
g_signal_connect (window,
|
||||
"tabs_reordered",
|
||||
G_CALLBACK (window_tabs_reordered),
|
||||
panel);
|
||||
g_signal_connect (window,
|
||||
"active_tab_changed",
|
||||
G_CALLBACK (window_active_tab_changed),
|
||||
panel);
|
||||
}
|
||||
|
||||
static void
|
||||
treeview_cursor_changed (GtkTreeView *view,
|
||||
XedDocumentsPanel *panel)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkTreeSelection *selection;
|
||||
gpointer tab;
|
||||
|
||||
selection = gtk_tree_view_get_selection (
|
||||
GTK_TREE_VIEW (panel->priv->treeview));
|
||||
|
||||
if (gtk_tree_selection_get_selected (selection, NULL, &iter))
|
||||
{
|
||||
gtk_tree_model_get (panel->priv->model,
|
||||
&iter,
|
||||
TAB_COLUMN,
|
||||
&tab,
|
||||
-1);
|
||||
|
||||
if (xed_window_get_active_tab (panel->priv->window) != tab)
|
||||
{
|
||||
xed_window_set_active_tab (panel->priv->window,
|
||||
XED_TAB (tab));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_documents_panel_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedDocumentsPanel *panel = XED_DOCUMENTS_PANEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_WINDOW:
|
||||
set_window (panel, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_documents_panel_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedDocumentsPanel *panel = XED_DOCUMENTS_PANEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_WINDOW:
|
||||
g_value_set_object (value,
|
||||
XED_DOCUMENTS_PANEL_GET_PRIVATE (panel)->window);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_documents_panel_finalize (GObject *object)
|
||||
{
|
||||
/* XedDocumentsPanel *tab = XED_DOCUMENTS_PANEL (object); */
|
||||
|
||||
/* TODO: disconnect signal with window */
|
||||
|
||||
G_OBJECT_CLASS (xed_documents_panel_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_documents_panel_dispose (GObject *object)
|
||||
{
|
||||
XedDocumentsPanel *panel = XED_DOCUMENTS_PANEL (object);
|
||||
|
||||
if (panel->priv->window != NULL)
|
||||
{
|
||||
g_object_unref (panel->priv->window);
|
||||
panel->priv->window = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (xed_documents_panel_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_documents_panel_class_init (XedDocumentsPanelClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = xed_documents_panel_finalize;
|
||||
object_class->dispose = xed_documents_panel_dispose;
|
||||
object_class->get_property = xed_documents_panel_get_property;
|
||||
object_class->set_property = xed_documents_panel_set_property;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_WINDOW,
|
||||
g_param_spec_object ("window",
|
||||
"Window",
|
||||
"The XedWindow this XedDocumentsPanel is associated with",
|
||||
XED_TYPE_WINDOW,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (XedDocumentsPanelPrivate));
|
||||
}
|
||||
|
||||
static GtkTreePath *
|
||||
get_current_path (XedDocumentsPanel *panel)
|
||||
{
|
||||
gint num;
|
||||
GtkWidget *nb;
|
||||
GtkTreePath *path;
|
||||
|
||||
nb = _xed_window_get_notebook (panel->priv->window);
|
||||
num = gtk_notebook_get_current_page (GTK_NOTEBOOK (nb));
|
||||
|
||||
path = gtk_tree_path_new_from_indices (num, -1);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static void
|
||||
menu_position (GtkMenu *menu,
|
||||
gint *x,
|
||||
gint *y,
|
||||
gboolean *push_in,
|
||||
XedDocumentsPanel *panel)
|
||||
{
|
||||
GtkTreePath *path;
|
||||
GdkRectangle rect;
|
||||
gint wx, wy;
|
||||
GtkAllocation allocation;
|
||||
GtkRequisition requisition;
|
||||
GtkWidget *w;
|
||||
|
||||
w = panel->priv->treeview;
|
||||
|
||||
gtk_widget_get_allocation(w, &allocation);
|
||||
|
||||
path = get_current_path (panel);
|
||||
|
||||
gtk_tree_view_get_cell_area (GTK_TREE_VIEW (w),
|
||||
path,
|
||||
NULL,
|
||||
&rect);
|
||||
|
||||
wx = rect.x;
|
||||
wy = rect.y;
|
||||
|
||||
gdk_window_get_origin (gtk_widget_get_window (w), x, y);
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &requisition);
|
||||
#else
|
||||
gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
|
||||
#endif
|
||||
|
||||
if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
|
||||
{
|
||||
*x += allocation.x + allocation.width - requisition.width - 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x += allocation.x + 10;
|
||||
}
|
||||
|
||||
wy = MAX (*y + 5, *y + wy + 5);
|
||||
wy = MIN (wy, *y + allocation.height - requisition.height - 5);
|
||||
|
||||
*y = wy;
|
||||
|
||||
*push_in = TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
show_popup_menu (XedDocumentsPanel *panel,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkWidget *menu;
|
||||
|
||||
menu = gtk_ui_manager_get_widget (xed_window_get_ui_manager (panel->priv->window),
|
||||
"/NotebookPopup");
|
||||
g_return_val_if_fail (menu != NULL, FALSE);
|
||||
|
||||
if (event != NULL)
|
||||
{
|
||||
gtk_menu_popup (GTK_MENU (menu),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
event->button,
|
||||
event->time);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_menu_popup (GTK_MENU (menu),
|
||||
NULL,
|
||||
NULL,
|
||||
(GtkMenuPositionFunc) menu_position,
|
||||
panel,
|
||||
0,
|
||||
gtk_get_current_event_time ());
|
||||
|
||||
gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
panel_button_press_event (GtkTreeView *treeview,
|
||||
GdkEventButton *event,
|
||||
XedDocumentsPanel *panel)
|
||||
{
|
||||
if ((GDK_BUTTON_PRESS == event->type) && (3 == event->button))
|
||||
{
|
||||
GtkTreePath* path = NULL;
|
||||
|
||||
if (event->window == gtk_tree_view_get_bin_window (treeview))
|
||||
{
|
||||
/* Change the cursor position */
|
||||
if (gtk_tree_view_get_path_at_pos (treeview,
|
||||
event->x,
|
||||
event->y,
|
||||
&path,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL))
|
||||
{
|
||||
|
||||
gtk_tree_view_set_cursor (treeview,
|
||||
path,
|
||||
NULL,
|
||||
FALSE);
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
|
||||
/* A row exists at mouse position */
|
||||
return show_popup_menu (panel, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
panel_popup_menu (GtkWidget *treeview,
|
||||
XedDocumentsPanel *panel)
|
||||
{
|
||||
/* Only respond if the treeview is the actual focus */
|
||||
if (gtk_window_get_focus (GTK_WINDOW (panel->priv->window)) == treeview)
|
||||
{
|
||||
return show_popup_menu (panel, NULL);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
treeview_query_tooltip (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
gboolean keyboard_tip,
|
||||
GtkTooltip *tooltip,
|
||||
gpointer data)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
|
||||
GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
|
||||
GtkTreePath *path = NULL;
|
||||
gpointer *tab;
|
||||
gchar *tip;
|
||||
|
||||
if (keyboard_tip)
|
||||
{
|
||||
gtk_tree_view_get_cursor (tree_view, &path, NULL);
|
||||
|
||||
if (path == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint bin_x, bin_y;
|
||||
|
||||
gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
|
||||
x, y,
|
||||
&bin_x, &bin_y);
|
||||
|
||||
if (!gtk_tree_view_get_path_at_pos (tree_view,
|
||||
bin_x, bin_y,
|
||||
&path,
|
||||
NULL, NULL, NULL))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_tree_model_get_iter (model, &iter, path);
|
||||
gtk_tree_model_get (model,
|
||||
&iter,
|
||||
TAB_COLUMN,
|
||||
&tab,
|
||||
-1);
|
||||
|
||||
tip = _xed_tab_get_tooltips (XED_TAB (tab));
|
||||
gtk_tooltip_set_markup (tooltip, tip);
|
||||
|
||||
g_free (tip);
|
||||
gtk_tree_path_free (path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
treeview_row_inserted (GtkTreeModel *tree_model,
|
||||
GtkTreePath *path,
|
||||
GtkTreeIter *iter,
|
||||
XedDocumentsPanel *panel)
|
||||
{
|
||||
XedTab *tab;
|
||||
gint *indeces;
|
||||
GtkWidget *nb;
|
||||
gint old_position;
|
||||
gint new_position;
|
||||
|
||||
if (panel->priv->adding_tab)
|
||||
return;
|
||||
|
||||
tab = xed_window_get_active_tab (panel->priv->window);
|
||||
g_return_if_fail (tab != NULL);
|
||||
|
||||
panel->priv->is_reodering = TRUE;
|
||||
|
||||
indeces = gtk_tree_path_get_indices (path);
|
||||
|
||||
/* g_debug ("New Index: %d (path: %s)", indeces[0], gtk_tree_path_to_string (path));*/
|
||||
|
||||
nb = _xed_window_get_notebook (panel->priv->window);
|
||||
|
||||
new_position = indeces[0];
|
||||
old_position = gtk_notebook_page_num (GTK_NOTEBOOK (nb),
|
||||
GTK_WIDGET (tab));
|
||||
if (new_position > old_position)
|
||||
new_position = MAX (0, new_position - 1);
|
||||
|
||||
xed_notebook_reorder_tab (XED_NOTEBOOK (nb),
|
||||
tab,
|
||||
new_position);
|
||||
|
||||
panel->priv->is_reodering = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
xed_documents_panel_init (XedDocumentsPanel *panel)
|
||||
{
|
||||
GtkWidget *sw;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkCellRenderer *cell;
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
panel->priv = XED_DOCUMENTS_PANEL_GET_PRIVATE (panel);
|
||||
|
||||
panel->priv->adding_tab = FALSE;
|
||||
panel->priv->is_reodering = FALSE;
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (panel),
|
||||
GTK_ORIENTATION_VERTICAL);
|
||||
#endif
|
||||
|
||||
/* Create the scrolled window */
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
g_return_if_fail (sw != NULL);
|
||||
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_SHADOW_IN);
|
||||
gtk_widget_show (sw);
|
||||
gtk_box_pack_start (GTK_BOX (panel), sw, TRUE, TRUE, 0);
|
||||
|
||||
/* Create the empty model */
|
||||
panel->priv->model = GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS,
|
||||
GDK_TYPE_PIXBUF,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_POINTER));
|
||||
|
||||
/* Create the treeview */
|
||||
panel->priv->treeview = gtk_tree_view_new_with_model (panel->priv->model);
|
||||
g_object_unref (G_OBJECT (panel->priv->model));
|
||||
gtk_container_add (GTK_CONTAINER (sw), panel->priv->treeview);
|
||||
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (panel->priv->treeview), FALSE);
|
||||
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (panel->priv->treeview), TRUE);
|
||||
|
||||
g_object_set (panel->priv->treeview, "has-tooltip", TRUE, NULL);
|
||||
|
||||
gtk_widget_show (panel->priv->treeview);
|
||||
|
||||
column = gtk_tree_view_column_new ();
|
||||
gtk_tree_view_column_set_title (column, _("Documents"));
|
||||
|
||||
cell = gtk_cell_renderer_pixbuf_new ();
|
||||
gtk_tree_view_column_pack_start (column, cell, FALSE);
|
||||
gtk_tree_view_column_add_attribute (column, cell, "pixbuf", PIXBUF_COLUMN);
|
||||
cell = gtk_cell_renderer_text_new ();
|
||||
gtk_tree_view_column_pack_start (column, cell, TRUE);
|
||||
gtk_tree_view_column_add_attribute (column, cell, "markup", NAME_COLUMN);
|
||||
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (panel->priv->treeview),
|
||||
column);
|
||||
|
||||
selection = gtk_tree_view_get_selection (
|
||||
GTK_TREE_VIEW (panel->priv->treeview));
|
||||
|
||||
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
|
||||
|
||||
g_signal_connect (panel->priv->treeview,
|
||||
"cursor_changed",
|
||||
G_CALLBACK (treeview_cursor_changed),
|
||||
panel);
|
||||
g_signal_connect (panel->priv->treeview,
|
||||
"button-press-event",
|
||||
G_CALLBACK (panel_button_press_event),
|
||||
panel);
|
||||
g_signal_connect (panel->priv->treeview,
|
||||
"popup-menu",
|
||||
G_CALLBACK (panel_popup_menu),
|
||||
panel);
|
||||
g_signal_connect (panel->priv->treeview,
|
||||
"query-tooltip",
|
||||
G_CALLBACK (treeview_query_tooltip),
|
||||
NULL);
|
||||
|
||||
g_signal_connect (panel->priv->model,
|
||||
"row-inserted",
|
||||
G_CALLBACK (treeview_row_inserted),
|
||||
panel);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
xed_documents_panel_new (XedWindow *window)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_WINDOW (window), NULL);
|
||||
|
||||
return GTK_WIDGET (g_object_new (XED_TYPE_DOCUMENTS_PANEL,
|
||||
"window", window,
|
||||
NULL));
|
||||
}
|
||||
93
xed/xed-documents-panel.h
Normal file
93
xed/xed-documents-panel.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* xed-documents-panel.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_DOCUMENTS_PANEL_H__
|
||||
#define __XED_DOCUMENTS_PANEL_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <xed/xed-window.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_DOCUMENTS_PANEL (xed_documents_panel_get_type())
|
||||
#define XED_DOCUMENTS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_DOCUMENTS_PANEL, XedDocumentsPanel))
|
||||
#define XED_DOCUMENTS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_DOCUMENTS_PANEL, XedDocumentsPanelClass))
|
||||
#define XED_IS_DOCUMENTS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_DOCUMENTS_PANEL))
|
||||
#define XED_IS_DOCUMENTS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_DOCUMENTS_PANEL))
|
||||
#define XED_DOCUMENTS_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_DOCUMENTS_PANEL, XedDocumentsPanelClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedDocumentsPanelPrivate XedDocumentsPanelPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedDocumentsPanel XedDocumentsPanel;
|
||||
|
||||
struct _XedDocumentsPanel
|
||||
{
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
GtkBox vbox;
|
||||
#else
|
||||
GtkVBox vbox;
|
||||
#endif
|
||||
|
||||
/*< private > */
|
||||
XedDocumentsPanelPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedDocumentsPanelClass XedDocumentsPanelClass;
|
||||
|
||||
struct _XedDocumentsPanelClass
|
||||
{
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
GtkBoxClass parent_class;
|
||||
#else
|
||||
GtkVBoxClass parent_class;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_documents_panel_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget *xed_documents_panel_new (XedWindow *window);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_DOCUMENTS_PANEL_H__ */
|
||||
469
xed/xed-encodings-combo-box.c
Normal file
469
xed/xed-encodings-combo-box.c
Normal file
@@ -0,0 +1,469 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* xed-encodings-combo-box.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2003-2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2003-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id: xed-encodings-combo-box.c 6112 2008-01-23 08:26:24Z sfre $
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <xed/xed-encodings-combo-box.h>
|
||||
#include <xed/xed-prefs-manager.h>
|
||||
#include <xed/dialogs/xed-encodings-dialog.h>
|
||||
|
||||
#define ENCODING_KEY "Enconding"
|
||||
|
||||
#define XED_ENCODINGS_COMBO_BOX_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
|
||||
XED_TYPE_ENCODINGS_COMBO_BOX, \
|
||||
XedEncodingsComboBoxPrivate))
|
||||
|
||||
struct _XedEncodingsComboBoxPrivate
|
||||
{
|
||||
GtkListStore *store;
|
||||
glong changed_id;
|
||||
|
||||
guint activated_item;
|
||||
|
||||
guint save_mode : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NAME_COLUMN,
|
||||
ENCODING_COLUMN,
|
||||
ADD_COLUMN,
|
||||
N_COLUMNS
|
||||
};
|
||||
|
||||
/* Properties */
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_SAVE_MODE
|
||||
};
|
||||
|
||||
|
||||
G_DEFINE_TYPE(XedEncodingsComboBox, xed_encodings_combo_box, GTK_TYPE_COMBO_BOX)
|
||||
|
||||
static void update_menu (XedEncodingsComboBox *combo_box);
|
||||
|
||||
static void
|
||||
xed_encodings_combo_box_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedEncodingsComboBox *combo;
|
||||
|
||||
combo = XED_ENCODINGS_COMBO_BOX (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SAVE_MODE:
|
||||
combo->priv->save_mode = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_encodings_combo_box_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedEncodingsComboBox *combo;
|
||||
|
||||
combo = XED_ENCODINGS_COMBO_BOX (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SAVE_MODE:
|
||||
g_value_set_boolean (value, combo->priv->save_mode);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_encodings_combo_box_dispose (GObject *object)
|
||||
{
|
||||
XedEncodingsComboBox *combo = XED_ENCODINGS_COMBO_BOX (object);
|
||||
|
||||
if (combo->priv->store != NULL)
|
||||
{
|
||||
g_object_unref (combo->priv->store);
|
||||
combo->priv->store = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (xed_encodings_combo_box_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_encodings_combo_box_class_init (XedEncodingsComboBoxClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = xed_encodings_combo_box_set_property;
|
||||
object_class->get_property = xed_encodings_combo_box_get_property;
|
||||
object_class->dispose = xed_encodings_combo_box_dispose;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_SAVE_MODE,
|
||||
g_param_spec_boolean ("save-mode",
|
||||
"Save Mode",
|
||||
"Save Mode",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (XedEncodingsComboBoxPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
dialog_response_cb (GtkDialog *dialog,
|
||||
gint response_id,
|
||||
XedEncodingsComboBox *menu)
|
||||
{
|
||||
if (response_id == GTK_RESPONSE_OK)
|
||||
{
|
||||
update_menu (menu);
|
||||
}
|
||||
|
||||
gtk_widget_destroy (GTK_WIDGET (dialog));
|
||||
}
|
||||
|
||||
static void
|
||||
add_or_remove (XedEncodingsComboBox *menu,
|
||||
GtkTreeModel *model)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
gboolean add_item = FALSE;
|
||||
|
||||
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (menu), &iter))
|
||||
{
|
||||
gtk_tree_model_get (model, &iter,
|
||||
ADD_COLUMN, &add_item,
|
||||
-1);
|
||||
}
|
||||
|
||||
if (!add_item)
|
||||
{
|
||||
menu->priv->activated_item = gtk_combo_box_get_active (GTK_COMBO_BOX (menu));
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menu));
|
||||
|
||||
if (!gtk_widget_is_toplevel (toplevel))
|
||||
toplevel = NULL;
|
||||
|
||||
g_signal_handler_block (menu, menu->priv->changed_id);
|
||||
gtk_combo_box_set_active (GTK_COMBO_BOX (menu),
|
||||
menu->priv->activated_item);
|
||||
g_signal_handler_unblock (menu, menu->priv->changed_id);
|
||||
|
||||
dialog = xed_encodings_dialog_new();
|
||||
|
||||
if (toplevel != NULL)
|
||||
{
|
||||
GtkWindowGroup *wg;
|
||||
|
||||
gtk_window_set_transient_for (GTK_WINDOW (dialog),
|
||||
GTK_WINDOW (toplevel));
|
||||
|
||||
wg = gtk_window_get_group (GTK_WINDOW (toplevel));
|
||||
if (wg == NULL)
|
||||
{
|
||||
wg = gtk_window_group_new ();
|
||||
gtk_window_group_add_window (wg,
|
||||
GTK_WINDOW (toplevel));
|
||||
}
|
||||
|
||||
gtk_window_group_add_window (wg,
|
||||
GTK_WINDOW (dialog));
|
||||
}
|
||||
|
||||
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
|
||||
|
||||
g_signal_connect (dialog,
|
||||
"response",
|
||||
G_CALLBACK (dialog_response_cb),
|
||||
menu);
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
separator_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
|
||||
{
|
||||
gchar *str;
|
||||
gboolean ret;
|
||||
|
||||
gtk_tree_model_get (model, iter, NAME_COLUMN, &str, -1);
|
||||
ret = (str == NULL || *str == '\0');
|
||||
g_free (str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
update_menu (XedEncodingsComboBox *menu)
|
||||
{
|
||||
GtkListStore *store;
|
||||
GtkTreeIter iter;
|
||||
GSList *encodings, *l;
|
||||
gchar *str;
|
||||
const XedEncoding *utf8_encoding;
|
||||
const XedEncoding *current_encoding;
|
||||
|
||||
store = menu->priv->store;
|
||||
|
||||
/* Unset the previous model */
|
||||
g_signal_handler_block (menu, menu->priv->changed_id);
|
||||
gtk_list_store_clear (store);
|
||||
gtk_combo_box_set_model (GTK_COMBO_BOX (menu),
|
||||
NULL);
|
||||
|
||||
utf8_encoding = xed_encoding_get_utf8 ();
|
||||
current_encoding = xed_encoding_get_current ();
|
||||
|
||||
if (!menu->priv->save_mode)
|
||||
{
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter,
|
||||
NAME_COLUMN, _("Automatically Detected"),
|
||||
ENCODING_COLUMN, NULL,
|
||||
ADD_COLUMN, FALSE,
|
||||
-1);
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter,
|
||||
NAME_COLUMN, "",
|
||||
ENCODING_COLUMN, NULL,
|
||||
ADD_COLUMN, FALSE,
|
||||
-1);
|
||||
}
|
||||
|
||||
if (current_encoding != utf8_encoding)
|
||||
str = xed_encoding_to_string (utf8_encoding);
|
||||
else
|
||||
str = g_strdup_printf (_("Current Locale (%s)"),
|
||||
xed_encoding_get_charset (utf8_encoding));
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter,
|
||||
NAME_COLUMN, str,
|
||||
ENCODING_COLUMN, utf8_encoding,
|
||||
ADD_COLUMN, FALSE,
|
||||
-1);
|
||||
|
||||
g_free (str);
|
||||
|
||||
if ((utf8_encoding != current_encoding) &&
|
||||
(current_encoding != NULL))
|
||||
{
|
||||
str = g_strdup_printf (_("Current Locale (%s)"),
|
||||
xed_encoding_get_charset (current_encoding));
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter,
|
||||
NAME_COLUMN, str,
|
||||
ENCODING_COLUMN, current_encoding,
|
||||
ADD_COLUMN, FALSE,
|
||||
-1);
|
||||
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
encodings = xed_prefs_manager_get_shown_in_menu_encodings ();
|
||||
|
||||
for (l = encodings; l != NULL; l = g_slist_next (l))
|
||||
{
|
||||
const XedEncoding *enc = (const XedEncoding *)l->data;
|
||||
|
||||
if ((enc != current_encoding) &&
|
||||
(enc != utf8_encoding) &&
|
||||
(enc != NULL))
|
||||
{
|
||||
str = xed_encoding_to_string (enc);
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter,
|
||||
NAME_COLUMN, str,
|
||||
ENCODING_COLUMN, enc,
|
||||
ADD_COLUMN, FALSE,
|
||||
-1);
|
||||
|
||||
g_free (str);
|
||||
}
|
||||
}
|
||||
|
||||
g_slist_free (encodings);
|
||||
|
||||
if (xed_prefs_manager_shown_in_menu_encodings_can_set ())
|
||||
{
|
||||
gtk_list_store_append (store, &iter);
|
||||
/* separator */
|
||||
gtk_list_store_set (store, &iter,
|
||||
NAME_COLUMN, "",
|
||||
ENCODING_COLUMN, NULL,
|
||||
ADD_COLUMN, FALSE,
|
||||
-1);
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter,
|
||||
NAME_COLUMN, _("Add or Remove..."),
|
||||
ENCODING_COLUMN, NULL,
|
||||
ADD_COLUMN, TRUE,
|
||||
-1);
|
||||
}
|
||||
|
||||
/* set the model back */
|
||||
gtk_combo_box_set_model (GTK_COMBO_BOX (menu),
|
||||
GTK_TREE_MODEL (menu->priv->store));
|
||||
gtk_combo_box_set_active (GTK_COMBO_BOX (menu), 0);
|
||||
|
||||
g_signal_handler_unblock (menu, menu->priv->changed_id);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_encodings_combo_box_init (XedEncodingsComboBox *menu)
|
||||
{
|
||||
GtkCellRenderer *text_renderer;
|
||||
|
||||
menu->priv = XED_ENCODINGS_COMBO_BOX_GET_PRIVATE (menu);
|
||||
|
||||
menu->priv->store = gtk_list_store_new (N_COLUMNS,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_POINTER,
|
||||
G_TYPE_BOOLEAN);
|
||||
|
||||
/* Setup up the cells */
|
||||
text_renderer = gtk_cell_renderer_text_new ();
|
||||
gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (menu),
|
||||
text_renderer, TRUE);
|
||||
|
||||
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (menu),
|
||||
text_renderer,
|
||||
"text",
|
||||
NAME_COLUMN,
|
||||
NULL);
|
||||
|
||||
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (menu),
|
||||
separator_func, NULL,
|
||||
NULL);
|
||||
|
||||
menu->priv->changed_id = g_signal_connect (menu, "changed",
|
||||
G_CALLBACK (add_or_remove),
|
||||
menu->priv->store);
|
||||
|
||||
update_menu (menu);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
xed_encodings_combo_box_new (gboolean save_mode)
|
||||
{
|
||||
return g_object_new (XED_TYPE_ENCODINGS_COMBO_BOX,
|
||||
"save_mode", save_mode,
|
||||
NULL);
|
||||
}
|
||||
|
||||
const XedEncoding *
|
||||
xed_encodings_combo_box_get_selected_encoding (XedEncodingsComboBox *menu)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
|
||||
g_return_val_if_fail (XED_IS_ENCODINGS_COMBO_BOX (menu), NULL);
|
||||
|
||||
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (menu), &iter))
|
||||
{
|
||||
const XedEncoding *ret;
|
||||
GtkTreeModel *model;
|
||||
|
||||
model = gtk_combo_box_get_model (GTK_COMBO_BOX (menu));
|
||||
|
||||
gtk_tree_model_get (model, &iter,
|
||||
ENCODING_COLUMN, &ret,
|
||||
-1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_encodings_combo_box_set_selected_encoding:
|
||||
* @menu:
|
||||
* @encoding: (allow-none):
|
||||
**/
|
||||
void
|
||||
xed_encodings_combo_box_set_selected_encoding (XedEncodingsComboBox *menu,
|
||||
const XedEncoding *encoding)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
gboolean b;
|
||||
g_return_if_fail (XED_IS_ENCODINGS_COMBO_BOX (menu));
|
||||
g_return_if_fail (GTK_IS_COMBO_BOX (menu));
|
||||
|
||||
model = gtk_combo_box_get_model (GTK_COMBO_BOX (menu));
|
||||
b = gtk_tree_model_get_iter_first (model, &iter);
|
||||
|
||||
while (b)
|
||||
{
|
||||
const XedEncoding *enc;
|
||||
|
||||
gtk_tree_model_get (model, &iter,
|
||||
ENCODING_COLUMN, &enc,
|
||||
-1);
|
||||
|
||||
if (enc == encoding)
|
||||
{
|
||||
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (menu),
|
||||
&iter);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
b = gtk_tree_model_iter_next (model, &iter);
|
||||
}
|
||||
}
|
||||
78
xed/xed-encodings-combo-box.h
Normal file
78
xed/xed-encodings-combo-box.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* xed-encodings-combo-box.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2003-2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2003-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id: xed-encodings-option-menu.h 4429 2005-12-12 17:28:04Z pborelli $
|
||||
*/
|
||||
|
||||
#ifndef __XED_ENCODINGS_COMBO_BOX_H__
|
||||
#define __XED_ENCODINGS_COMBO_BOX_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <xed/xed-encodings.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_ENCODINGS_COMBO_BOX (xed_encodings_combo_box_get_type ())
|
||||
#define XED_ENCODINGS_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_ENCODINGS_COMBO_BOX, XedEncodingsComboBox))
|
||||
#define XED_ENCODINGS_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_ENCODINGS_COMBO_BOX, XedEncodingsComboBoxClass))
|
||||
#define XED_IS_ENCODINGS_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_ENCODINGS_COMBO_BOX))
|
||||
#define XED_IS_ENCODINGS_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_ENCODINGS_COMBO_BOX))
|
||||
#define XED_ENCODINGS_COMBO_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_ENCODINGS_COMBO_BOX, XedEncodingsComboBoxClass))
|
||||
|
||||
|
||||
typedef struct _XedEncodingsComboBox XedEncodingsComboBox;
|
||||
typedef struct _XedEncodingsComboBoxClass XedEncodingsComboBoxClass;
|
||||
|
||||
typedef struct _XedEncodingsComboBoxPrivate XedEncodingsComboBoxPrivate;
|
||||
|
||||
struct _XedEncodingsComboBox
|
||||
{
|
||||
GtkComboBox parent;
|
||||
|
||||
XedEncodingsComboBoxPrivate *priv;
|
||||
};
|
||||
|
||||
struct _XedEncodingsComboBoxClass
|
||||
{
|
||||
GtkComboBoxClass parent_class;
|
||||
};
|
||||
|
||||
GType xed_encodings_combo_box_get_type (void) G_GNUC_CONST;
|
||||
|
||||
/* Constructor */
|
||||
GtkWidget *xed_encodings_combo_box_new (gboolean save_mode);
|
||||
|
||||
const XedEncoding *xed_encodings_combo_box_get_selected_encoding (XedEncodingsComboBox *menu);
|
||||
void xed_encodings_combo_box_set_selected_encoding (XedEncodingsComboBox *menu,
|
||||
const XedEncoding *encoding);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_ENCODINGS_COMBO_BOX_H__ */
|
||||
|
||||
|
||||
473
xed/xed-encodings.c
Normal file
473
xed/xed-encodings.c
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* xed-encodings.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "xed-encodings.h"
|
||||
|
||||
|
||||
struct _XedEncoding
|
||||
{
|
||||
gint index;
|
||||
const gchar *charset;
|
||||
const gchar *name;
|
||||
};
|
||||
|
||||
/*
|
||||
* The original versions of the following tables are taken from profterm
|
||||
*
|
||||
* Copyright (C) 2002 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
||||
XED_ENCODING_ISO_8859_1,
|
||||
XED_ENCODING_ISO_8859_2,
|
||||
XED_ENCODING_ISO_8859_3,
|
||||
XED_ENCODING_ISO_8859_4,
|
||||
XED_ENCODING_ISO_8859_5,
|
||||
XED_ENCODING_ISO_8859_6,
|
||||
XED_ENCODING_ISO_8859_7,
|
||||
XED_ENCODING_ISO_8859_8,
|
||||
XED_ENCODING_ISO_8859_9,
|
||||
XED_ENCODING_ISO_8859_10,
|
||||
XED_ENCODING_ISO_8859_13,
|
||||
XED_ENCODING_ISO_8859_14,
|
||||
XED_ENCODING_ISO_8859_15,
|
||||
XED_ENCODING_ISO_8859_16,
|
||||
|
||||
XED_ENCODING_UTF_7,
|
||||
XED_ENCODING_UTF_16,
|
||||
XED_ENCODING_UTF_16_BE,
|
||||
XED_ENCODING_UTF_16_LE,
|
||||
XED_ENCODING_UTF_32,
|
||||
XED_ENCODING_UCS_2,
|
||||
XED_ENCODING_UCS_4,
|
||||
|
||||
XED_ENCODING_ARMSCII_8,
|
||||
XED_ENCODING_BIG5,
|
||||
XED_ENCODING_BIG5_HKSCS,
|
||||
XED_ENCODING_CP_866,
|
||||
|
||||
XED_ENCODING_EUC_JP,
|
||||
XED_ENCODING_EUC_JP_MS,
|
||||
XED_ENCODING_CP932,
|
||||
XED_ENCODING_EUC_KR,
|
||||
XED_ENCODING_EUC_TW,
|
||||
|
||||
XED_ENCODING_GB18030,
|
||||
XED_ENCODING_GB2312,
|
||||
XED_ENCODING_GBK,
|
||||
XED_ENCODING_GEOSTD8,
|
||||
|
||||
XED_ENCODING_IBM_850,
|
||||
XED_ENCODING_IBM_852,
|
||||
XED_ENCODING_IBM_855,
|
||||
XED_ENCODING_IBM_857,
|
||||
XED_ENCODING_IBM_862,
|
||||
XED_ENCODING_IBM_864,
|
||||
|
||||
XED_ENCODING_ISO_2022_JP,
|
||||
XED_ENCODING_ISO_2022_KR,
|
||||
XED_ENCODING_ISO_IR_111,
|
||||
XED_ENCODING_JOHAB,
|
||||
XED_ENCODING_KOI8_R,
|
||||
XED_ENCODING_KOI8__R,
|
||||
XED_ENCODING_KOI8_U,
|
||||
|
||||
XED_ENCODING_SHIFT_JIS,
|
||||
XED_ENCODING_TCVN,
|
||||
XED_ENCODING_TIS_620,
|
||||
XED_ENCODING_UHC,
|
||||
XED_ENCODING_VISCII,
|
||||
|
||||
XED_ENCODING_WINDOWS_1250,
|
||||
XED_ENCODING_WINDOWS_1251,
|
||||
XED_ENCODING_WINDOWS_1252,
|
||||
XED_ENCODING_WINDOWS_1253,
|
||||
XED_ENCODING_WINDOWS_1254,
|
||||
XED_ENCODING_WINDOWS_1255,
|
||||
XED_ENCODING_WINDOWS_1256,
|
||||
XED_ENCODING_WINDOWS_1257,
|
||||
XED_ENCODING_WINDOWS_1258,
|
||||
|
||||
XED_ENCODING_LAST,
|
||||
|
||||
XED_ENCODING_UTF_8,
|
||||
XED_ENCODING_UNKNOWN
|
||||
|
||||
} XedEncodingIndex;
|
||||
|
||||
static const XedEncoding utf8_encoding = {
|
||||
XED_ENCODING_UTF_8,
|
||||
"UTF-8",
|
||||
N_("Unicode")
|
||||
};
|
||||
|
||||
/* initialized in xed_encoding_lazy_init() */
|
||||
static XedEncoding unknown_encoding = {
|
||||
XED_ENCODING_UNKNOWN,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const XedEncoding encodings [] = {
|
||||
|
||||
{ XED_ENCODING_ISO_8859_1,
|
||||
"ISO-8859-1", N_("Western") },
|
||||
{ XED_ENCODING_ISO_8859_2,
|
||||
"ISO-8859-2", N_("Central European") },
|
||||
{ XED_ENCODING_ISO_8859_3,
|
||||
"ISO-8859-3", N_("South European") },
|
||||
{ XED_ENCODING_ISO_8859_4,
|
||||
"ISO-8859-4", N_("Baltic") },
|
||||
{ XED_ENCODING_ISO_8859_5,
|
||||
"ISO-8859-5", N_("Cyrillic") },
|
||||
{ XED_ENCODING_ISO_8859_6,
|
||||
"ISO-8859-6", N_("Arabic") },
|
||||
{ XED_ENCODING_ISO_8859_7,
|
||||
"ISO-8859-7", N_("Greek") },
|
||||
{ XED_ENCODING_ISO_8859_8,
|
||||
"ISO-8859-8", N_("Hebrew Visual") },
|
||||
{ XED_ENCODING_ISO_8859_9,
|
||||
"ISO-8859-9", N_("Turkish") },
|
||||
{ XED_ENCODING_ISO_8859_10,
|
||||
"ISO-8859-10", N_("Nordic") },
|
||||
{ XED_ENCODING_ISO_8859_13,
|
||||
"ISO-8859-13", N_("Baltic") },
|
||||
{ XED_ENCODING_ISO_8859_14,
|
||||
"ISO-8859-14", N_("Celtic") },
|
||||
{ XED_ENCODING_ISO_8859_15,
|
||||
"ISO-8859-15", N_("Western") },
|
||||
{ XED_ENCODING_ISO_8859_16,
|
||||
"ISO-8859-16", N_("Romanian") },
|
||||
|
||||
{ XED_ENCODING_UTF_7,
|
||||
"UTF-7", N_("Unicode") },
|
||||
{ XED_ENCODING_UTF_16,
|
||||
"UTF-16", N_("Unicode") },
|
||||
{ XED_ENCODING_UTF_16_BE,
|
||||
"UTF-16BE", N_("Unicode") },
|
||||
{ XED_ENCODING_UTF_16_LE,
|
||||
"UTF-16LE", N_("Unicode") },
|
||||
{ XED_ENCODING_UTF_32,
|
||||
"UTF-32", N_("Unicode") },
|
||||
{ XED_ENCODING_UCS_2,
|
||||
"UCS-2", N_("Unicode") },
|
||||
{ XED_ENCODING_UCS_4,
|
||||
"UCS-4", N_("Unicode") },
|
||||
|
||||
{ XED_ENCODING_ARMSCII_8,
|
||||
"ARMSCII-8", N_("Armenian") },
|
||||
{ XED_ENCODING_BIG5,
|
||||
"BIG5", N_("Chinese Traditional") },
|
||||
{ XED_ENCODING_BIG5_HKSCS,
|
||||
"BIG5-HKSCS", N_("Chinese Traditional") },
|
||||
{ XED_ENCODING_CP_866,
|
||||
"CP866", N_("Cyrillic/Russian") },
|
||||
|
||||
{ XED_ENCODING_EUC_JP,
|
||||
"EUC-JP", N_("Japanese") },
|
||||
{ XED_ENCODING_EUC_JP_MS,
|
||||
"EUC-JP-MS", N_("Japanese") },
|
||||
{ XED_ENCODING_CP932,
|
||||
"CP932", N_("Japanese") },
|
||||
|
||||
{ XED_ENCODING_EUC_KR,
|
||||
"EUC-KR", N_("Korean") },
|
||||
{ XED_ENCODING_EUC_TW,
|
||||
"EUC-TW", N_("Chinese Traditional") },
|
||||
|
||||
{ XED_ENCODING_GB18030,
|
||||
"GB18030", N_("Chinese Simplified") },
|
||||
{ XED_ENCODING_GB2312,
|
||||
"GB2312", N_("Chinese Simplified") },
|
||||
{ XED_ENCODING_GBK,
|
||||
"GBK", N_("Chinese Simplified") },
|
||||
{ XED_ENCODING_GEOSTD8,
|
||||
"GEORGIAN-ACADEMY", N_("Georgian") }, /* FIXME GEOSTD8 ? */
|
||||
|
||||
{ XED_ENCODING_IBM_850,
|
||||
"IBM850", N_("Western") },
|
||||
{ XED_ENCODING_IBM_852,
|
||||
"IBM852", N_("Central European") },
|
||||
{ XED_ENCODING_IBM_855,
|
||||
"IBM855", N_("Cyrillic") },
|
||||
{ XED_ENCODING_IBM_857,
|
||||
"IBM857", N_("Turkish") },
|
||||
{ XED_ENCODING_IBM_862,
|
||||
"IBM862", N_("Hebrew") },
|
||||
{ XED_ENCODING_IBM_864,
|
||||
"IBM864", N_("Arabic") },
|
||||
|
||||
{ XED_ENCODING_ISO_2022_JP,
|
||||
"ISO-2022-JP", N_("Japanese") },
|
||||
{ XED_ENCODING_ISO_2022_KR,
|
||||
"ISO-2022-KR", N_("Korean") },
|
||||
{ XED_ENCODING_ISO_IR_111,
|
||||
"ISO-IR-111", N_("Cyrillic") },
|
||||
{ XED_ENCODING_JOHAB,
|
||||
"JOHAB", N_("Korean") },
|
||||
{ XED_ENCODING_KOI8_R,
|
||||
"KOI8R", N_("Cyrillic") },
|
||||
{ XED_ENCODING_KOI8__R,
|
||||
"KOI8-R", N_("Cyrillic") },
|
||||
{ XED_ENCODING_KOI8_U,
|
||||
"KOI8U", N_("Cyrillic/Ukrainian") },
|
||||
|
||||
{ XED_ENCODING_SHIFT_JIS,
|
||||
"SHIFT_JIS", N_("Japanese") },
|
||||
{ XED_ENCODING_TCVN,
|
||||
"TCVN", N_("Vietnamese") },
|
||||
{ XED_ENCODING_TIS_620,
|
||||
"TIS-620", N_("Thai") },
|
||||
{ XED_ENCODING_UHC,
|
||||
"UHC", N_("Korean") },
|
||||
{ XED_ENCODING_VISCII,
|
||||
"VISCII", N_("Vietnamese") },
|
||||
|
||||
{ XED_ENCODING_WINDOWS_1250,
|
||||
"WINDOWS-1250", N_("Central European") },
|
||||
{ XED_ENCODING_WINDOWS_1251,
|
||||
"WINDOWS-1251", N_("Cyrillic") },
|
||||
{ XED_ENCODING_WINDOWS_1252,
|
||||
"WINDOWS-1252", N_("Western") },
|
||||
{ XED_ENCODING_WINDOWS_1253,
|
||||
"WINDOWS-1253", N_("Greek") },
|
||||
{ XED_ENCODING_WINDOWS_1254,
|
||||
"WINDOWS-1254", N_("Turkish") },
|
||||
{ XED_ENCODING_WINDOWS_1255,
|
||||
"WINDOWS-1255", N_("Hebrew") },
|
||||
{ XED_ENCODING_WINDOWS_1256,
|
||||
"WINDOWS-1256", N_("Arabic") },
|
||||
{ XED_ENCODING_WINDOWS_1257,
|
||||
"WINDOWS-1257", N_("Baltic") },
|
||||
{ XED_ENCODING_WINDOWS_1258,
|
||||
"WINDOWS-1258", N_("Vietnamese") }
|
||||
};
|
||||
|
||||
static void
|
||||
xed_encoding_lazy_init (void)
|
||||
{
|
||||
static gboolean initialized = FALSE;
|
||||
const gchar *locale_charset;
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
if (g_get_charset (&locale_charset) == FALSE)
|
||||
{
|
||||
unknown_encoding.charset = g_strdup (locale_charset);
|
||||
}
|
||||
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
||||
const XedEncoding *
|
||||
xed_encoding_get_from_charset (const gchar *charset)
|
||||
{
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (charset != NULL, NULL);
|
||||
|
||||
xed_encoding_lazy_init ();
|
||||
|
||||
if (charset == NULL)
|
||||
return NULL;
|
||||
|
||||
if (g_ascii_strcasecmp (charset, "UTF-8") == 0)
|
||||
return xed_encoding_get_utf8 ();
|
||||
|
||||
i = 0;
|
||||
while (i < XED_ENCODING_LAST)
|
||||
{
|
||||
if (g_ascii_strcasecmp (charset, encodings[i].charset) == 0)
|
||||
return &encodings[i];
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (unknown_encoding.charset != NULL)
|
||||
{
|
||||
if (g_ascii_strcasecmp (charset, unknown_encoding.charset) == 0)
|
||||
return &unknown_encoding;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const XedEncoding *
|
||||
xed_encoding_get_from_index (gint idx)
|
||||
{
|
||||
g_return_val_if_fail (idx >= 0, NULL);
|
||||
|
||||
if (idx >= XED_ENCODING_LAST)
|
||||
return NULL;
|
||||
|
||||
xed_encoding_lazy_init ();
|
||||
|
||||
return &encodings[idx];
|
||||
}
|
||||
|
||||
const XedEncoding *
|
||||
xed_encoding_get_utf8 (void)
|
||||
{
|
||||
xed_encoding_lazy_init ();
|
||||
|
||||
return &utf8_encoding;
|
||||
}
|
||||
|
||||
const XedEncoding *
|
||||
xed_encoding_get_current (void)
|
||||
{
|
||||
static gboolean initialized = FALSE;
|
||||
static const XedEncoding *locale_encoding = NULL;
|
||||
|
||||
const gchar *locale_charset;
|
||||
|
||||
xed_encoding_lazy_init ();
|
||||
|
||||
if (initialized != FALSE)
|
||||
return locale_encoding;
|
||||
|
||||
if (g_get_charset (&locale_charset) == FALSE)
|
||||
{
|
||||
g_return_val_if_fail (locale_charset != NULL, &utf8_encoding);
|
||||
|
||||
locale_encoding = xed_encoding_get_from_charset (locale_charset);
|
||||
}
|
||||
else
|
||||
{
|
||||
locale_encoding = &utf8_encoding;
|
||||
}
|
||||
|
||||
if (locale_encoding == NULL)
|
||||
{
|
||||
locale_encoding = &unknown_encoding;
|
||||
}
|
||||
|
||||
g_return_val_if_fail (locale_encoding != NULL, NULL);
|
||||
|
||||
initialized = TRUE;
|
||||
|
||||
return locale_encoding;
|
||||
}
|
||||
|
||||
gchar *
|
||||
xed_encoding_to_string (const XedEncoding* enc)
|
||||
{
|
||||
g_return_val_if_fail (enc != NULL, NULL);
|
||||
|
||||
xed_encoding_lazy_init ();
|
||||
|
||||
g_return_val_if_fail (enc->charset != NULL, NULL);
|
||||
|
||||
if (enc->name != NULL)
|
||||
{
|
||||
return g_strdup_printf ("%s (%s)", _(enc->name), enc->charset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_ascii_strcasecmp (enc->charset, "ANSI_X3.4-1968") == 0)
|
||||
return g_strdup_printf ("US-ASCII (%s)", enc->charset);
|
||||
else
|
||||
return g_strdup (enc->charset);
|
||||
}
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_encoding_get_charset (const XedEncoding* enc)
|
||||
{
|
||||
g_return_val_if_fail (enc != NULL, NULL);
|
||||
|
||||
xed_encoding_lazy_init ();
|
||||
|
||||
g_return_val_if_fail (enc->charset != NULL, NULL);
|
||||
|
||||
return enc->charset;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_encoding_get_name (const XedEncoding* enc)
|
||||
{
|
||||
g_return_val_if_fail (enc != NULL, NULL);
|
||||
|
||||
xed_encoding_lazy_init ();
|
||||
|
||||
return (enc->name == NULL) ? _("Unknown") : _(enc->name);
|
||||
}
|
||||
|
||||
/* These are to make language bindings happy. Since Encodings are
|
||||
* const, copy() just returns the same pointer and fres() doesn't
|
||||
* do nothing */
|
||||
|
||||
XedEncoding *
|
||||
xed_encoding_copy (const XedEncoding *enc)
|
||||
{
|
||||
g_return_val_if_fail (enc != NULL, NULL);
|
||||
|
||||
return (XedEncoding *) enc;
|
||||
}
|
||||
|
||||
void
|
||||
xed_encoding_free (XedEncoding *enc)
|
||||
{
|
||||
g_return_if_fail (enc != NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_encoding_get_type:
|
||||
*
|
||||
* Retrieves the GType object which is associated with the
|
||||
* #XedEncoding class.
|
||||
*
|
||||
* Return value: the GType associated with #XedEncoding.
|
||||
**/
|
||||
GType
|
||||
xed_encoding_get_type (void)
|
||||
{
|
||||
static GType our_type = 0;
|
||||
|
||||
if (!our_type)
|
||||
our_type = g_boxed_type_register_static (
|
||||
"XedEncoding",
|
||||
(GBoxedCopyFunc) xed_encoding_copy,
|
||||
(GBoxedFreeFunc) xed_encoding_free);
|
||||
|
||||
return our_type;
|
||||
}
|
||||
|
||||
62
xed/xed-encodings.h
Normal file
62
xed/xed-encodings.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* xed-encodings.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_ENCODINGS_H__
|
||||
#define __XED_ENCODINGS_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _XedEncoding XedEncoding;
|
||||
|
||||
#define XED_TYPE_ENCODING (xed_encoding_get_type ())
|
||||
|
||||
GType xed_encoding_get_type (void) G_GNUC_CONST;
|
||||
|
||||
const XedEncoding *xed_encoding_get_from_charset (const gchar *charset);
|
||||
const XedEncoding *xed_encoding_get_from_index (gint index);
|
||||
|
||||
gchar *xed_encoding_to_string (const XedEncoding *enc);
|
||||
|
||||
const gchar *xed_encoding_get_name (const XedEncoding *enc);
|
||||
const gchar *xed_encoding_get_charset (const XedEncoding *enc);
|
||||
|
||||
const XedEncoding *xed_encoding_get_utf8 (void);
|
||||
const XedEncoding *xed_encoding_get_current (void);
|
||||
|
||||
/* These should not be used, they are just to make python bindings happy */
|
||||
XedEncoding *xed_encoding_copy (const XedEncoding *enc);
|
||||
void xed_encoding_free (XedEncoding *enc);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_ENCODINGS_H__ */
|
||||
39
xed/xed-enum-types.c.template
Normal file
39
xed/xed-enum-types.c.template
Normal file
@@ -0,0 +1,39 @@
|
||||
/*** BEGIN file-header ***/
|
||||
#include "xed-enum-types.h"
|
||||
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN file-production ***/
|
||||
/* enumerations from "@filename@" */
|
||||
#include "@filename@"
|
||||
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GType
|
||||
@enum_name@_get_type (void)
|
||||
{
|
||||
static GType the_type = 0;
|
||||
|
||||
if (the_type == 0)
|
||||
{
|
||||
static const G@Type@Value values[] = {
|
||||
/*** END value-header ***/
|
||||
|
||||
/*** BEGIN value-production ***/
|
||||
{ @VALUENAME@,
|
||||
"@VALUENAME@",
|
||||
"@valuenick@" },
|
||||
/*** END value-production ***/
|
||||
|
||||
/*** BEGIN value-tail ***/
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
the_type = g_@type@_register_static (
|
||||
g_intern_static_string ("@EnumName@"),
|
||||
values);
|
||||
}
|
||||
return the_type;
|
||||
}
|
||||
|
||||
/*** END value-tail ***/
|
||||
27
xed/xed-enum-types.h.template
Normal file
27
xed/xed-enum-types.h.template
Normal file
@@ -0,0 +1,27 @@
|
||||
/*** BEGIN file-header ***/
|
||||
#ifndef __XED_ENUM_TYPES_H__
|
||||
#define __XED_ENUM_TYPES_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN file-production ***/
|
||||
/* Enumerations from "@filename@" */
|
||||
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN enumeration-production ***/
|
||||
#define XED_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
|
||||
GType @enum_name@_get_type (void) G_GNUC_CONST;
|
||||
|
||||
/*** END enumeration-production ***/
|
||||
|
||||
/*** BEGIN file-tail ***/
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_ENUM_TYPES_H__ */
|
||||
/*** END file-tail ***/
|
||||
|
||||
586
xed/xed-file-chooser-dialog.c
Normal file
586
xed/xed-file-chooser-dialog.c
Normal file
@@ -0,0 +1,586 @@
|
||||
/*
|
||||
* xed-file-chooser-dialog.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005-2007 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005-2007. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* TODO: Override set_extra_widget */
|
||||
/* TODO: add encoding property */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
#include <gtksourceview/gtksource.h>
|
||||
#endif
|
||||
|
||||
#include "xed-file-chooser-dialog.h"
|
||||
#include "xed-encodings-combo-box.h"
|
||||
#include "xed-language-manager.h"
|
||||
#include "xed-prefs-manager-app.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-enum-types.h"
|
||||
|
||||
#define XED_FILE_CHOOSER_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_FILE_CHOOSER_DIALOG, XedFileChooserDialogPrivate))
|
||||
|
||||
#define ALL_FILES _("All Files")
|
||||
#define ALL_TEXT_FILES _("All Text Files")
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
#define gtk_hbox_new(X,Y) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,Y)
|
||||
#endif
|
||||
|
||||
struct _XedFileChooserDialogPrivate
|
||||
{
|
||||
GtkWidget *option_menu;
|
||||
GtkWidget *extra_widget;
|
||||
|
||||
GtkWidget *newline_label;
|
||||
GtkWidget *newline_combo;
|
||||
GtkListStore *newline_store;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(XedFileChooserDialog, xed_file_chooser_dialog, GTK_TYPE_FILE_CHOOSER_DIALOG)
|
||||
|
||||
static void
|
||||
xed_file_chooser_dialog_class_init (XedFileChooserDialogClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (object_class, sizeof(XedFileChooserDialogPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
create_option_menu (XedFileChooserDialog *dialog)
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkWidget *menu;
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("C_haracter Encoding:"));
|
||||
#if GTK_CHECK_VERSION (3, 16, 0)
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
|
||||
#endif
|
||||
|
||||
menu = xed_encodings_combo_box_new (
|
||||
gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) == GTK_FILE_CHOOSER_ACTION_SAVE);
|
||||
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), menu);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (dialog->priv->extra_widget),
|
||||
label,
|
||||
FALSE,
|
||||
TRUE,
|
||||
0);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (dialog->priv->extra_widget),
|
||||
menu,
|
||||
TRUE,
|
||||
TRUE,
|
||||
0);
|
||||
|
||||
gtk_widget_show (label);
|
||||
gtk_widget_show (menu);
|
||||
|
||||
dialog->priv->option_menu = menu;
|
||||
}
|
||||
|
||||
static void
|
||||
update_newline_visibility (XedFileChooserDialog *dialog)
|
||||
{
|
||||
if (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) == GTK_FILE_CHOOSER_ACTION_SAVE)
|
||||
{
|
||||
gtk_widget_show (dialog->priv->newline_label);
|
||||
gtk_widget_show (dialog->priv->newline_combo);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_hide (dialog->priv->newline_label);
|
||||
gtk_widget_hide (dialog->priv->newline_combo);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
newline_combo_append (GtkComboBox *combo,
|
||||
GtkListStore *store,
|
||||
GtkTreeIter *iter,
|
||||
const gchar *label,
|
||||
XedDocumentNewlineType newline_type)
|
||||
{
|
||||
gtk_list_store_append (store, iter);
|
||||
gtk_list_store_set (store, iter, 0, label, 1, newline_type, -1);
|
||||
|
||||
if (newline_type == XED_DOCUMENT_NEWLINE_TYPE_DEFAULT)
|
||||
{
|
||||
gtk_combo_box_set_active_iter (combo, iter);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
create_newline_combo (XedFileChooserDialog *dialog)
|
||||
{
|
||||
GtkWidget *label, *combo;
|
||||
GtkListStore *store;
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeIter iter;
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("L_ine Ending:"));
|
||||
#if GTK_CHECK_VERSION (3, 16, 0)
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
|
||||
#endif
|
||||
|
||||
store = gtk_list_store_new (2, G_TYPE_STRING, XED_TYPE_DOCUMENT_NEWLINE_TYPE);
|
||||
combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
|
||||
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo),
|
||||
renderer,
|
||||
TRUE);
|
||||
|
||||
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo),
|
||||
renderer,
|
||||
"text",
|
||||
0);
|
||||
|
||||
newline_combo_append (GTK_COMBO_BOX (combo),
|
||||
store,
|
||||
&iter,
|
||||
_("Unix/Linux"),
|
||||
XED_DOCUMENT_NEWLINE_TYPE_LF);
|
||||
|
||||
newline_combo_append (GTK_COMBO_BOX (combo),
|
||||
store,
|
||||
&iter,
|
||||
_("Mac OS Classic"),
|
||||
XED_DOCUMENT_NEWLINE_TYPE_CR);
|
||||
|
||||
newline_combo_append (GTK_COMBO_BOX (combo),
|
||||
store,
|
||||
&iter,
|
||||
_("Windows"),
|
||||
XED_DOCUMENT_NEWLINE_TYPE_CR_LF);
|
||||
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (dialog->priv->extra_widget),
|
||||
label,
|
||||
FALSE,
|
||||
TRUE,
|
||||
0);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (dialog->priv->extra_widget),
|
||||
combo,
|
||||
TRUE,
|
||||
TRUE,
|
||||
0);
|
||||
|
||||
dialog->priv->newline_combo = combo;
|
||||
dialog->priv->newline_label = label;
|
||||
dialog->priv->newline_store = store;
|
||||
|
||||
update_newline_visibility (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
create_extra_widget (XedFileChooserDialog *dialog)
|
||||
{
|
||||
dialog->priv->extra_widget = gtk_hbox_new (FALSE, 6);
|
||||
|
||||
gtk_widget_show (dialog->priv->extra_widget);
|
||||
|
||||
create_option_menu (dialog);
|
||||
create_newline_combo (dialog);
|
||||
|
||||
gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog),
|
||||
dialog->priv->extra_widget);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
action_changed (XedFileChooserDialog *dialog,
|
||||
GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
GtkFileChooserAction action;
|
||||
|
||||
action = gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog));
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case GTK_FILE_CHOOSER_ACTION_OPEN:
|
||||
g_object_set (dialog->priv->option_menu,
|
||||
"save_mode", FALSE,
|
||||
NULL);
|
||||
gtk_widget_show (dialog->priv->option_menu);
|
||||
break;
|
||||
case GTK_FILE_CHOOSER_ACTION_SAVE:
|
||||
g_object_set (dialog->priv->option_menu,
|
||||
"save_mode", TRUE,
|
||||
NULL);
|
||||
gtk_widget_show (dialog->priv->option_menu);
|
||||
break;
|
||||
default:
|
||||
gtk_widget_hide (dialog->priv->option_menu);
|
||||
}
|
||||
|
||||
update_newline_visibility (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
filter_changed (XedFileChooserDialog *dialog,
|
||||
GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
GtkFileFilter *filter;
|
||||
|
||||
if (!xed_prefs_manager_active_file_filter_can_set ())
|
||||
return;
|
||||
|
||||
filter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (dialog));
|
||||
if (filter != NULL)
|
||||
{
|
||||
const gchar *name;
|
||||
gint id = 0;
|
||||
|
||||
name = gtk_file_filter_get_name (filter);
|
||||
g_return_if_fail (name != NULL);
|
||||
|
||||
if (strcmp (name, ALL_TEXT_FILES) == 0)
|
||||
id = 1;
|
||||
|
||||
xed_debug_message (DEBUG_COMMANDS, "Active filter: %s (%d)", name, id);
|
||||
|
||||
xed_prefs_manager_set_active_file_filter (id);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: use globs too - Paolo (Aug. 27, 2007) */
|
||||
static gboolean
|
||||
all_text_files_filter (const GtkFileFilterInfo *filter_info,
|
||||
gpointer data)
|
||||
{
|
||||
static GSList *known_mime_types = NULL;
|
||||
GSList *mime_types;
|
||||
|
||||
if (known_mime_types == NULL)
|
||||
{
|
||||
GtkSourceLanguageManager *lm;
|
||||
const gchar * const *languages;
|
||||
|
||||
lm = xed_get_language_manager ();
|
||||
languages = gtk_source_language_manager_get_language_ids (lm);
|
||||
|
||||
while ((languages != NULL) && (*languages != NULL))
|
||||
{
|
||||
gchar **mime_types;
|
||||
gint i;
|
||||
GtkSourceLanguage *lang;
|
||||
|
||||
lang = gtk_source_language_manager_get_language (lm, *languages);
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
g_return_val_if_fail (GTK_SOURCE_IS_LANGUAGE (lang), FALSE);
|
||||
#else
|
||||
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (lang), FALSE);
|
||||
#endif
|
||||
++languages;
|
||||
|
||||
mime_types = gtk_source_language_get_mime_types (lang);
|
||||
if (mime_types == NULL)
|
||||
continue;
|
||||
|
||||
for (i = 0; mime_types[i] != NULL; i++)
|
||||
{
|
||||
if (!g_content_type_is_a (mime_types[i], "text/plain"))
|
||||
{
|
||||
xed_debug_message (DEBUG_COMMANDS,
|
||||
"Mime-type %s is not related to text/plain",
|
||||
mime_types[i]);
|
||||
|
||||
known_mime_types = g_slist_prepend (known_mime_types,
|
||||
g_strdup (mime_types[i]));
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev (mime_types);
|
||||
}
|
||||
|
||||
/* known_mime_types always has "text/plain" as first item" */
|
||||
known_mime_types = g_slist_prepend (known_mime_types, g_strdup ("text/plain"));
|
||||
}
|
||||
|
||||
/* known mime_types contains "text/plain" and then the list of mime-types unrelated to "text/plain"
|
||||
* that xed recognizes */
|
||||
|
||||
if (filter_info->mime_type == NULL)
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* The filter is matching:
|
||||
* - the mime-types beginning with "text/"
|
||||
* - the mime-types inheriting from a known mime-type (note the text/plain is
|
||||
* the first known mime-type)
|
||||
*/
|
||||
|
||||
if (strncmp (filter_info->mime_type, "text/", 5) == 0)
|
||||
return TRUE;
|
||||
|
||||
mime_types = known_mime_types;
|
||||
while (mime_types != NULL)
|
||||
{
|
||||
if (g_content_type_is_a (filter_info->mime_type, (const gchar*)mime_types->data))
|
||||
return TRUE;
|
||||
|
||||
mime_types = g_slist_next (mime_types);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
xed_file_chooser_dialog_init (XedFileChooserDialog *dialog)
|
||||
{
|
||||
dialog->priv = XED_FILE_CHOOSER_DIALOG_GET_PRIVATE (dialog);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
xed_file_chooser_dialog_new_valist (const gchar *title,
|
||||
GtkWindow *parent,
|
||||
GtkFileChooserAction action,
|
||||
const XedEncoding *encoding,
|
||||
const gchar *first_button_text,
|
||||
va_list varargs)
|
||||
{
|
||||
GtkWidget *result;
|
||||
const char *button_text = first_button_text;
|
||||
gint response_id;
|
||||
GtkFileFilter *filter;
|
||||
gint active_filter;
|
||||
|
||||
g_return_val_if_fail (parent != NULL, NULL);
|
||||
|
||||
result = g_object_new (XED_TYPE_FILE_CHOOSER_DIALOG,
|
||||
"title", title,
|
||||
#if !GTK_CHECK_VERSION (3, 0, 0)
|
||||
"file-system-backend", NULL,
|
||||
#endif
|
||||
"local-only", FALSE,
|
||||
"action", action,
|
||||
"select-multiple", action == GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
NULL);
|
||||
|
||||
create_extra_widget (XED_FILE_CHOOSER_DIALOG (result));
|
||||
|
||||
g_signal_connect (result,
|
||||
"notify::action",
|
||||
G_CALLBACK (action_changed),
|
||||
NULL);
|
||||
|
||||
if (encoding != NULL)
|
||||
xed_encodings_combo_box_set_selected_encoding (
|
||||
XED_ENCODINGS_COMBO_BOX (XED_FILE_CHOOSER_DIALOG (result)->priv->option_menu),
|
||||
encoding);
|
||||
|
||||
active_filter = xed_prefs_manager_get_active_file_filter ();
|
||||
xed_debug_message (DEBUG_COMMANDS, "Active filter: %d", active_filter);
|
||||
|
||||
/* Filters */
|
||||
filter = gtk_file_filter_new ();
|
||||
|
||||
gtk_file_filter_set_name (filter, ALL_FILES);
|
||||
gtk_file_filter_add_pattern (filter, "*");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (result), filter);
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
gtk_file_chooser_set_action (GTK_FILE_CHOOSER (result), action);
|
||||
#endif
|
||||
|
||||
if (active_filter != 1)
|
||||
{
|
||||
/* Make this filter the default */
|
||||
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (result), filter);
|
||||
}
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, ALL_TEXT_FILES);
|
||||
gtk_file_filter_add_custom (filter,
|
||||
GTK_FILE_FILTER_MIME_TYPE,
|
||||
all_text_files_filter,
|
||||
NULL,
|
||||
NULL);
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (result), filter);
|
||||
|
||||
if (active_filter == 1)
|
||||
{
|
||||
/* Make this filter the default */
|
||||
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (result), filter);
|
||||
}
|
||||
|
||||
g_signal_connect (result,
|
||||
"notify::filter",
|
||||
G_CALLBACK (filter_changed),
|
||||
NULL);
|
||||
|
||||
gtk_window_set_transient_for (GTK_WINDOW (result), parent);
|
||||
gtk_window_set_destroy_with_parent (GTK_WINDOW (result), TRUE);
|
||||
|
||||
while (button_text)
|
||||
{
|
||||
response_id = va_arg (varargs, gint);
|
||||
|
||||
gtk_dialog_add_button (GTK_DIALOG (result), button_text, response_id);
|
||||
if ((response_id == GTK_RESPONSE_OK) ||
|
||||
(response_id == GTK_RESPONSE_ACCEPT) ||
|
||||
(response_id == GTK_RESPONSE_YES) ||
|
||||
(response_id == GTK_RESPONSE_APPLY))
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (result), response_id);
|
||||
|
||||
button_text = va_arg (varargs, const gchar *);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_file_chooser_dialog_new:
|
||||
* @title: (allow-none): Title of the dialog, or %NULL
|
||||
* @parent: (allow-none): Transient parent of the dialog, or %NULL
|
||||
* @action: Open or save mode for the dialog
|
||||
* @first_button_text: (allow-none): stock ID or text to go in
|
||||
* the first button, or %NULL
|
||||
* @Varargs: (allow-none): response ID for the first button, then
|
||||
* additional (button, id) pairs, ending with %NULL
|
||||
*
|
||||
* Creates a new #XedFileChooserDialog. This function is analogous to
|
||||
* gtk_dialog_new_with_buttons().
|
||||
*
|
||||
* Return value: a new #XedFileChooserDialog
|
||||
*
|
||||
**/
|
||||
GtkWidget *
|
||||
xed_file_chooser_dialog_new (const gchar *title,
|
||||
GtkWindow *parent,
|
||||
GtkFileChooserAction action,
|
||||
const XedEncoding *encoding,
|
||||
const gchar *first_button_text,
|
||||
...)
|
||||
{
|
||||
GtkWidget *result;
|
||||
va_list varargs;
|
||||
|
||||
va_start (varargs, first_button_text);
|
||||
result = xed_file_chooser_dialog_new_valist (title, parent, action,
|
||||
encoding, first_button_text,
|
||||
varargs);
|
||||
va_end (varargs);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
xed_file_chooser_dialog_set_encoding (XedFileChooserDialog *dialog,
|
||||
const XedEncoding *encoding)
|
||||
{
|
||||
g_return_if_fail (XED_IS_FILE_CHOOSER_DIALOG (dialog));
|
||||
g_return_if_fail (XED_IS_ENCODINGS_COMBO_BOX (dialog->priv->option_menu));
|
||||
|
||||
xed_encodings_combo_box_set_selected_encoding (
|
||||
XED_ENCODINGS_COMBO_BOX (dialog->priv->option_menu),
|
||||
encoding);
|
||||
}
|
||||
|
||||
const XedEncoding *
|
||||
xed_file_chooser_dialog_get_encoding (XedFileChooserDialog *dialog)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_FILE_CHOOSER_DIALOG (dialog), NULL);
|
||||
g_return_val_if_fail (XED_IS_ENCODINGS_COMBO_BOX (dialog->priv->option_menu), NULL);
|
||||
g_return_val_if_fail ((gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) == GTK_FILE_CHOOSER_ACTION_OPEN ||
|
||||
gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) == GTK_FILE_CHOOSER_ACTION_SAVE), NULL);
|
||||
|
||||
return xed_encodings_combo_box_get_selected_encoding (
|
||||
XED_ENCODINGS_COMBO_BOX (dialog->priv->option_menu));
|
||||
}
|
||||
|
||||
void
|
||||
xed_file_chooser_dialog_set_newline_type (XedFileChooserDialog *dialog,
|
||||
XedDocumentNewlineType newline_type)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
|
||||
g_return_if_fail (XED_IS_FILE_CHOOSER_DIALOG (dialog));
|
||||
g_return_if_fail (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) == GTK_FILE_CHOOSER_ACTION_SAVE);
|
||||
|
||||
model = GTK_TREE_MODEL (dialog->priv->newline_store);
|
||||
|
||||
if (!gtk_tree_model_get_iter_first (model, &iter))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
XedDocumentNewlineType nt;
|
||||
|
||||
gtk_tree_model_get (model, &iter, 1, &nt, -1);
|
||||
|
||||
if (newline_type == nt)
|
||||
{
|
||||
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (dialog->priv->newline_combo),
|
||||
&iter);
|
||||
break;
|
||||
}
|
||||
} while (gtk_tree_model_iter_next (model, &iter));
|
||||
}
|
||||
|
||||
XedDocumentNewlineType
|
||||
xed_file_chooser_dialog_get_newline_type (XedFileChooserDialog *dialog)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
XedDocumentNewlineType newline_type;
|
||||
|
||||
g_return_val_if_fail (XED_IS_FILE_CHOOSER_DIALOG (dialog), XED_DOCUMENT_NEWLINE_TYPE_DEFAULT);
|
||||
g_return_val_if_fail (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) == GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
XED_DOCUMENT_NEWLINE_TYPE_DEFAULT);
|
||||
|
||||
gtk_combo_box_get_active_iter (GTK_COMBO_BOX (dialog->priv->newline_combo),
|
||||
&iter);
|
||||
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->newline_store),
|
||||
&iter,
|
||||
1,
|
||||
&newline_type,
|
||||
-1);
|
||||
|
||||
return newline_type;
|
||||
}
|
||||
89
xed/xed-file-chooser-dialog.h
Normal file
89
xed/xed-file-chooser-dialog.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* xed-file-chooser-dialog.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_FILE_CHOOSER_DIALOG_H__
|
||||
#define __XED_FILE_CHOOSER_DIALOG_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <xed/xed-encodings.h>
|
||||
#include <xed/xed-enum-types.h>
|
||||
#include <xed/xed-document.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_FILE_CHOOSER_DIALOG (xed_file_chooser_dialog_get_type ())
|
||||
#define XED_FILE_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_FILE_CHOOSER_DIALOG, XedFileChooserDialog))
|
||||
#define XED_FILE_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_FILE_CHOOSER_DIALOG, XedFileChooserDialogClass))
|
||||
#define XED_IS_FILE_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_FILE_CHOOSER_DIALOG))
|
||||
#define XED_IS_FILE_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_FILE_CHOOSER_DIALOG))
|
||||
#define XED_FILE_CHOOSER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_FILE_CHOOSER_DIALOG, XedFileChooserDialogClass))
|
||||
|
||||
typedef struct _XedFileChooserDialog XedFileChooserDialog;
|
||||
typedef struct _XedFileChooserDialogClass XedFileChooserDialogClass;
|
||||
|
||||
typedef struct _XedFileChooserDialogPrivate XedFileChooserDialogPrivate;
|
||||
|
||||
struct _XedFileChooserDialogClass
|
||||
{
|
||||
GtkFileChooserDialogClass parent_class;
|
||||
};
|
||||
|
||||
struct _XedFileChooserDialog
|
||||
{
|
||||
GtkFileChooserDialog parent_instance;
|
||||
|
||||
XedFileChooserDialogPrivate *priv;
|
||||
};
|
||||
|
||||
GType xed_file_chooser_dialog_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget *xed_file_chooser_dialog_new (const gchar *title,
|
||||
GtkWindow *parent,
|
||||
GtkFileChooserAction action,
|
||||
const XedEncoding *encoding,
|
||||
const gchar *first_button_text,
|
||||
...);
|
||||
|
||||
void xed_file_chooser_dialog_set_encoding (XedFileChooserDialog *dialog,
|
||||
const XedEncoding *encoding);
|
||||
|
||||
const XedEncoding
|
||||
*xed_file_chooser_dialog_get_encoding (XedFileChooserDialog *dialog);
|
||||
|
||||
void xed_file_chooser_dialog_set_newline_type (XedFileChooserDialog *dialog,
|
||||
XedDocumentNewlineType newline_type);
|
||||
|
||||
XedDocumentNewlineType
|
||||
xed_file_chooser_dialog_get_newline_type (XedFileChooserDialog *dialog);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_FILE_CHOOSER_DIALOG_H__ */
|
||||
712
xed/xed-gio-document-loader.c
Normal file
712
xed/xed-gio-document-loader.c
Normal file
@@ -0,0 +1,712 @@
|
||||
/*
|
||||
* xed-gio-document-loader.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
* Copyright (C) 2007 - Paolo Maggi, Steve Frécinaux
|
||||
* Copyright (C) 2008 - Jesse van den Kieboom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005-2008. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "xed-gio-document-loader.h"
|
||||
#include "xed-document-output-stream.h"
|
||||
#include "xed-smart-charset-converter.h"
|
||||
#include "xed-prefs-manager.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-utils.h"
|
||||
|
||||
#ifndef ENABLE_GVFS_METADATA
|
||||
#include "xed-metadata-manager.h"
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
XedGioDocumentLoader *loader;
|
||||
GCancellable *cancellable;
|
||||
|
||||
gssize read;
|
||||
gboolean tried_mount;
|
||||
} AsyncData;
|
||||
|
||||
#define READ_CHUNK_SIZE 8192
|
||||
#define REMOTE_QUERY_ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \
|
||||
G_FILE_ATTRIBUTE_STANDARD_TYPE "," \
|
||||
G_FILE_ATTRIBUTE_TIME_MODIFIED "," \
|
||||
G_FILE_ATTRIBUTE_STANDARD_SIZE "," \
|
||||
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE "," \
|
||||
XED_METADATA_ATTRIBUTE_ENCODING
|
||||
|
||||
#define XED_GIO_DOCUMENT_LOADER_GET_PRIVATE(object) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
|
||||
XED_TYPE_GIO_DOCUMENT_LOADER, \
|
||||
XedGioDocumentLoaderPrivate))
|
||||
|
||||
static void xed_gio_document_loader_load (XedDocumentLoader *loader);
|
||||
static gboolean xed_gio_document_loader_cancel (XedDocumentLoader *loader);
|
||||
static goffset xed_gio_document_loader_get_bytes_read (XedDocumentLoader *loader);
|
||||
|
||||
static void open_async_read (AsyncData *async);
|
||||
|
||||
struct _XedGioDocumentLoaderPrivate
|
||||
{
|
||||
/* Info on the current file */
|
||||
GFile *gfile;
|
||||
|
||||
goffset bytes_read;
|
||||
|
||||
/* Handle for remote files */
|
||||
GCancellable *cancellable;
|
||||
GInputStream *stream;
|
||||
GOutputStream *output;
|
||||
XedSmartCharsetConverter *converter;
|
||||
|
||||
gchar buffer[READ_CHUNK_SIZE];
|
||||
|
||||
GError *error;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(XedGioDocumentLoader, xed_gio_document_loader, XED_TYPE_DOCUMENT_LOADER)
|
||||
|
||||
static void
|
||||
xed_gio_document_loader_dispose (GObject *object)
|
||||
{
|
||||
XedGioDocumentLoaderPrivate *priv;
|
||||
|
||||
priv = XED_GIO_DOCUMENT_LOADER (object)->priv;
|
||||
|
||||
if (priv->cancellable != NULL)
|
||||
{
|
||||
g_cancellable_cancel (priv->cancellable);
|
||||
g_object_unref (priv->cancellable);
|
||||
priv->cancellable = NULL;
|
||||
}
|
||||
|
||||
if (priv->stream != NULL)
|
||||
{
|
||||
g_object_unref (priv->stream);
|
||||
priv->stream = NULL;
|
||||
}
|
||||
|
||||
if (priv->output != NULL)
|
||||
{
|
||||
g_object_unref (priv->output);
|
||||
priv->output = NULL;
|
||||
}
|
||||
|
||||
if (priv->converter != NULL)
|
||||
{
|
||||
g_object_unref (priv->converter);
|
||||
priv->converter = NULL;
|
||||
}
|
||||
|
||||
if (priv->gfile != NULL)
|
||||
{
|
||||
g_object_unref (priv->gfile);
|
||||
priv->gfile = NULL;
|
||||
}
|
||||
|
||||
if (priv->error != NULL)
|
||||
{
|
||||
g_error_free (priv->error);
|
||||
priv->error = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (xed_gio_document_loader_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_gio_document_loader_class_init (XedGioDocumentLoaderClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
XedDocumentLoaderClass *loader_class = XED_DOCUMENT_LOADER_CLASS (klass);
|
||||
|
||||
object_class->dispose = xed_gio_document_loader_dispose;
|
||||
|
||||
loader_class->load = xed_gio_document_loader_load;
|
||||
loader_class->cancel = xed_gio_document_loader_cancel;
|
||||
loader_class->get_bytes_read = xed_gio_document_loader_get_bytes_read;
|
||||
|
||||
g_type_class_add_private (object_class, sizeof(XedGioDocumentLoaderPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
xed_gio_document_loader_init (XedGioDocumentLoader *gvloader)
|
||||
{
|
||||
gvloader->priv = XED_GIO_DOCUMENT_LOADER_GET_PRIVATE (gvloader);
|
||||
|
||||
gvloader->priv->converter = NULL;
|
||||
gvloader->priv->error = NULL;
|
||||
}
|
||||
|
||||
static AsyncData *
|
||||
async_data_new (XedGioDocumentLoader *gvloader)
|
||||
{
|
||||
AsyncData *async;
|
||||
|
||||
async = g_slice_new (AsyncData);
|
||||
async->loader = gvloader;
|
||||
async->cancellable = g_object_ref (gvloader->priv->cancellable);
|
||||
async->tried_mount = FALSE;
|
||||
|
||||
return async;
|
||||
}
|
||||
|
||||
static void
|
||||
async_data_free (AsyncData *async)
|
||||
{
|
||||
g_object_unref (async->cancellable);
|
||||
g_slice_free (AsyncData, async);
|
||||
}
|
||||
|
||||
static const XedEncoding *
|
||||
get_metadata_encoding (XedDocumentLoader *loader)
|
||||
{
|
||||
const XedEncoding *enc = NULL;
|
||||
|
||||
#ifndef ENABLE_GVFS_METADATA
|
||||
gchar *charset;
|
||||
const gchar *uri;
|
||||
|
||||
uri = xed_document_loader_get_uri (loader);
|
||||
|
||||
charset = xed_metadata_manager_get (uri, "encoding");
|
||||
|
||||
if (charset == NULL)
|
||||
return NULL;
|
||||
|
||||
enc = xed_encoding_get_from_charset (charset);
|
||||
|
||||
g_free (charset);
|
||||
#else
|
||||
GFileInfo *info;
|
||||
|
||||
info = xed_document_loader_get_info (loader);
|
||||
|
||||
/* check if the encoding was set in the metadata */
|
||||
if (g_file_info_has_attribute (info, XED_METADATA_ATTRIBUTE_ENCODING))
|
||||
{
|
||||
const gchar *charset;
|
||||
|
||||
charset = g_file_info_get_attribute_string (info,
|
||||
XED_METADATA_ATTRIBUTE_ENCODING);
|
||||
|
||||
if (charset == NULL)
|
||||
return NULL;
|
||||
|
||||
enc = xed_encoding_get_from_charset (charset);
|
||||
}
|
||||
#endif
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
static void
|
||||
remote_load_completed_or_failed (XedGioDocumentLoader *loader, AsyncData *async)
|
||||
{
|
||||
xed_document_loader_loading (XED_DOCUMENT_LOADER (loader),
|
||||
TRUE,
|
||||
loader->priv->error);
|
||||
|
||||
if (async)
|
||||
async_data_free (async);
|
||||
}
|
||||
|
||||
static void
|
||||
async_failed (AsyncData *async, GError *error)
|
||||
{
|
||||
g_propagate_error (&async->loader->priv->error, error);
|
||||
remote_load_completed_or_failed (async->loader, async);
|
||||
}
|
||||
|
||||
static void
|
||||
close_input_stream_ready_cb (GInputStream *stream,
|
||||
GAsyncResult *res,
|
||||
AsyncData *async)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
xed_debug (DEBUG_LOADER);
|
||||
|
||||
/* check cancelled state manually */
|
||||
if (g_cancellable_is_cancelled (async->cancellable))
|
||||
{
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
xed_debug_message (DEBUG_SAVER, "Finished closing input stream");
|
||||
|
||||
if (!g_input_stream_close_finish (stream, res, &error))
|
||||
{
|
||||
xed_debug_message (DEBUG_SAVER, "Closing input stream error: %s", error->message);
|
||||
|
||||
async_failed (async, error);
|
||||
return;
|
||||
}
|
||||
|
||||
xed_debug_message (DEBUG_SAVER, "Close output stream");
|
||||
if (!g_output_stream_close (async->loader->priv->output,
|
||||
async->cancellable, &error))
|
||||
{
|
||||
async_failed (async, error);
|
||||
return;
|
||||
}
|
||||
|
||||
remote_load_completed_or_failed (async->loader, async);
|
||||
}
|
||||
|
||||
static void
|
||||
write_complete (AsyncData *async)
|
||||
{
|
||||
XedDocumentLoader *loader;
|
||||
|
||||
loader = XED_DOCUMENT_LOADER (async->loader);
|
||||
|
||||
if (async->loader->priv->stream)
|
||||
g_input_stream_close_async (G_INPUT_STREAM (async->loader->priv->stream),
|
||||
G_PRIORITY_HIGH,
|
||||
async->cancellable,
|
||||
(GAsyncReadyCallback)close_input_stream_ready_cb,
|
||||
async);
|
||||
}
|
||||
|
||||
/* prototype, because they call each other... isn't C lovely */
|
||||
static void read_file_chunk (AsyncData *async);
|
||||
|
||||
static void
|
||||
write_file_chunk (AsyncData *async)
|
||||
{
|
||||
XedGioDocumentLoader *gvloader;
|
||||
gssize bytes_written;
|
||||
GError *error = NULL;
|
||||
|
||||
gvloader = async->loader;
|
||||
|
||||
/* we use sync methods on doc stream since it is in memory. Using async
|
||||
would be racy and we can endup with invalidated iters */
|
||||
bytes_written = g_output_stream_write (G_OUTPUT_STREAM (gvloader->priv->output),
|
||||
gvloader->priv->buffer,
|
||||
async->read,
|
||||
async->cancellable,
|
||||
&error);
|
||||
|
||||
xed_debug_message (DEBUG_SAVER, "Written: %" G_GSSIZE_FORMAT, bytes_written);
|
||||
if (bytes_written == -1)
|
||||
{
|
||||
xed_debug_message (DEBUG_SAVER, "Write error: %s", error->message);
|
||||
async_failed (async, error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* note that this signal blocks the read... check if it isn't
|
||||
* a performance problem
|
||||
*/
|
||||
xed_document_loader_loading (XED_DOCUMENT_LOADER (gvloader),
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
read_file_chunk (async);
|
||||
}
|
||||
|
||||
static void
|
||||
async_read_cb (GInputStream *stream,
|
||||
GAsyncResult *res,
|
||||
AsyncData *async)
|
||||
{
|
||||
xed_debug (DEBUG_LOADER);
|
||||
XedGioDocumentLoader *gvloader;
|
||||
GError *error = NULL;
|
||||
|
||||
xed_debug (DEBUG_LOADER);
|
||||
|
||||
/* manually check cancelled state */
|
||||
if (g_cancellable_is_cancelled (async->cancellable))
|
||||
{
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
gvloader = async->loader;
|
||||
|
||||
async->read = g_input_stream_read_finish (stream, res, &error);
|
||||
|
||||
/* error occurred */
|
||||
if (async->read == -1)
|
||||
{
|
||||
async_failed (async, error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for the extremely unlikely case where the file size overflows. */
|
||||
if (gvloader->priv->bytes_read + async->read < gvloader->priv->bytes_read)
|
||||
{
|
||||
g_set_error (&gvloader->priv->error,
|
||||
XED_DOCUMENT_ERROR,
|
||||
XED_DOCUMENT_ERROR_TOO_BIG,
|
||||
"File too big");
|
||||
|
||||
async_failed (async, gvloader->priv->error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Bump the size. */
|
||||
gvloader->priv->bytes_read += async->read;
|
||||
|
||||
/* end of the file, we are done! */
|
||||
if (async->read == 0)
|
||||
{
|
||||
XedDocumentLoader *loader;
|
||||
|
||||
loader = XED_DOCUMENT_LOADER (gvloader);
|
||||
|
||||
g_output_stream_flush (gvloader->priv->output,
|
||||
NULL,
|
||||
&gvloader->priv->error);
|
||||
|
||||
loader->auto_detected_encoding =
|
||||
xed_smart_charset_converter_get_guessed (gvloader->priv->converter);
|
||||
|
||||
loader->auto_detected_newline_type =
|
||||
xed_document_output_stream_detect_newline_type (XED_DOCUMENT_OUTPUT_STREAM (gvloader->priv->output));
|
||||
|
||||
/* Check if we needed some fallback char, if so, check if there was
|
||||
a previous error and if not set a fallback used error */
|
||||
/* FIXME Uncomment this when we want to manage conversion fallback */
|
||||
/*if ((xed_smart_charset_converter_get_num_fallbacks (gvloader->priv->converter) != 0) &&
|
||||
gvloader->priv->error == NULL)
|
||||
{
|
||||
g_set_error_literal (&gvloader->priv->error,
|
||||
XED_DOCUMENT_ERROR,
|
||||
XED_DOCUMENT_ERROR_CONVERSION_FALLBACK,
|
||||
"There was a conversion error and it was "
|
||||
"needed to use a fallback char");
|
||||
}*/
|
||||
|
||||
write_complete (async);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
write_file_chunk (async);
|
||||
}
|
||||
|
||||
static void
|
||||
read_file_chunk (AsyncData *async)
|
||||
{
|
||||
XedGioDocumentLoader *gvloader;
|
||||
|
||||
gvloader = async->loader;
|
||||
|
||||
g_input_stream_read_async (G_INPUT_STREAM (gvloader->priv->stream),
|
||||
gvloader->priv->buffer,
|
||||
READ_CHUNK_SIZE,
|
||||
G_PRIORITY_HIGH,
|
||||
async->cancellable,
|
||||
(GAsyncReadyCallback) async_read_cb,
|
||||
async);
|
||||
}
|
||||
|
||||
static GSList *
|
||||
get_candidate_encodings (XedGioDocumentLoader *gvloader)
|
||||
{
|
||||
const XedEncoding *metadata;
|
||||
GSList *encodings = NULL;
|
||||
|
||||
encodings = xed_prefs_manager_get_auto_detected_encodings ();
|
||||
|
||||
metadata = get_metadata_encoding (XED_DOCUMENT_LOADER (gvloader));
|
||||
if (metadata != NULL)
|
||||
{
|
||||
encodings = g_slist_prepend (encodings, (gpointer)metadata);
|
||||
}
|
||||
|
||||
return encodings;
|
||||
}
|
||||
|
||||
static void
|
||||
finish_query_info (AsyncData *async)
|
||||
{
|
||||
XedGioDocumentLoader *gvloader;
|
||||
XedDocumentLoader *loader;
|
||||
GInputStream *conv_stream;
|
||||
GFileInfo *info;
|
||||
GSList *candidate_encodings;
|
||||
|
||||
gvloader = async->loader;
|
||||
loader = XED_DOCUMENT_LOADER (gvloader);
|
||||
info = loader->info;
|
||||
|
||||
/* if it's not a regular file, error out... */
|
||||
if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) &&
|
||||
g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR)
|
||||
{
|
||||
g_set_error (&gvloader->priv->error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_REGULAR_FILE,
|
||||
"Not a regular file");
|
||||
|
||||
remote_load_completed_or_failed (gvloader, async);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the candidate encodings */
|
||||
if (loader->encoding == NULL)
|
||||
{
|
||||
candidate_encodings = get_candidate_encodings (gvloader);
|
||||
}
|
||||
else
|
||||
{
|
||||
candidate_encodings = g_slist_prepend (NULL, (gpointer) loader->encoding);
|
||||
}
|
||||
|
||||
gvloader->priv->converter = xed_smart_charset_converter_new (candidate_encodings);
|
||||
g_slist_free (candidate_encodings);
|
||||
|
||||
conv_stream = g_converter_input_stream_new (gvloader->priv->stream,
|
||||
G_CONVERTER (gvloader->priv->converter));
|
||||
g_object_unref (gvloader->priv->stream);
|
||||
|
||||
gvloader->priv->stream = conv_stream;
|
||||
|
||||
/* Output stream */
|
||||
gvloader->priv->output = xed_document_output_stream_new (loader->document);
|
||||
|
||||
/* start reading */
|
||||
read_file_chunk (async);
|
||||
}
|
||||
|
||||
static void
|
||||
query_info_cb (GFile *source,
|
||||
GAsyncResult *res,
|
||||
AsyncData *async)
|
||||
{
|
||||
XedGioDocumentLoader *gvloader;
|
||||
GFileInfo *info;
|
||||
GError *error = NULL;
|
||||
|
||||
xed_debug (DEBUG_LOADER);
|
||||
|
||||
/* manually check the cancelled state */
|
||||
if (g_cancellable_is_cancelled (async->cancellable))
|
||||
{
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
gvloader = async->loader;
|
||||
|
||||
/* finish the info query */
|
||||
info = g_file_query_info_finish (gvloader->priv->gfile,
|
||||
res,
|
||||
&error);
|
||||
|
||||
if (info == NULL)
|
||||
{
|
||||
/* propagate the error and clean up */
|
||||
async_failed (async, error);
|
||||
return;
|
||||
}
|
||||
|
||||
XED_DOCUMENT_LOADER (gvloader)->info = info;
|
||||
|
||||
finish_query_info (async);
|
||||
}
|
||||
|
||||
static void
|
||||
mount_ready_callback (GFile *file,
|
||||
GAsyncResult *res,
|
||||
AsyncData *async)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gboolean mounted;
|
||||
|
||||
xed_debug (DEBUG_LOADER);
|
||||
|
||||
/* manual check for cancelled state */
|
||||
if (g_cancellable_is_cancelled (async->cancellable))
|
||||
{
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
mounted = g_file_mount_enclosing_volume_finish (file, res, &error);
|
||||
|
||||
if (!mounted)
|
||||
{
|
||||
async_failed (async, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* try again to open the file for reading */
|
||||
open_async_read (async);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
recover_not_mounted (AsyncData *async)
|
||||
{
|
||||
XedDocument *doc;
|
||||
GMountOperation *mount_operation;
|
||||
|
||||
xed_debug (DEBUG_LOADER);
|
||||
|
||||
doc = xed_document_loader_get_document (XED_DOCUMENT_LOADER (async->loader));
|
||||
mount_operation = _xed_document_create_mount_operation (doc);
|
||||
|
||||
async->tried_mount = TRUE;
|
||||
g_file_mount_enclosing_volume (async->loader->priv->gfile,
|
||||
G_MOUNT_MOUNT_NONE,
|
||||
mount_operation,
|
||||
async->cancellable,
|
||||
(GAsyncReadyCallback) mount_ready_callback,
|
||||
async);
|
||||
|
||||
g_object_unref (mount_operation);
|
||||
}
|
||||
|
||||
static void
|
||||
async_read_ready_callback (GObject *source,
|
||||
GAsyncResult *res,
|
||||
AsyncData *async)
|
||||
{
|
||||
GError *error = NULL;
|
||||
XedGioDocumentLoader *gvloader;
|
||||
|
||||
xed_debug (DEBUG_LOADER);
|
||||
|
||||
/* manual check for cancelled state */
|
||||
if (g_cancellable_is_cancelled (async->cancellable))
|
||||
{
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
gvloader = async->loader;
|
||||
|
||||
gvloader->priv->stream = G_INPUT_STREAM (g_file_read_finish (gvloader->priv->gfile,
|
||||
res, &error));
|
||||
|
||||
if (!gvloader->priv->stream)
|
||||
{
|
||||
if (error->code == G_IO_ERROR_NOT_MOUNTED && !async->tried_mount)
|
||||
{
|
||||
recover_not_mounted (async);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Propagate error */
|
||||
g_propagate_error (&gvloader->priv->error, error);
|
||||
xed_document_loader_loading (XED_DOCUMENT_LOADER (gvloader),
|
||||
TRUE,
|
||||
gvloader->priv->error);
|
||||
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the file info: note we cannot use
|
||||
* g_file_input_stream_query_info_async since it is not able to get the
|
||||
* content type etc, beside it is not supported by gvfs.
|
||||
* Using the file instead of the stream is slightly racy, but for
|
||||
* loading this is not too bad...
|
||||
*/
|
||||
g_file_query_info_async (gvloader->priv->gfile,
|
||||
REMOTE_QUERY_ATTRIBUTES,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
G_PRIORITY_HIGH,
|
||||
async->cancellable,
|
||||
(GAsyncReadyCallback) query_info_cb,
|
||||
async);
|
||||
}
|
||||
|
||||
static void
|
||||
open_async_read (AsyncData *async)
|
||||
{
|
||||
g_file_read_async (async->loader->priv->gfile,
|
||||
G_PRIORITY_HIGH,
|
||||
async->cancellable,
|
||||
(GAsyncReadyCallback) async_read_ready_callback,
|
||||
async);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_gio_document_loader_load (XedDocumentLoader *loader)
|
||||
{
|
||||
XedGioDocumentLoader *gvloader = XED_GIO_DOCUMENT_LOADER (loader);
|
||||
AsyncData *async;
|
||||
|
||||
xed_debug (DEBUG_LOADER);
|
||||
|
||||
/* make sure no load operation is currently running */
|
||||
g_return_if_fail (gvloader->priv->cancellable == NULL);
|
||||
|
||||
gvloader->priv->gfile = g_file_new_for_uri (loader->uri);
|
||||
|
||||
/* loading start */
|
||||
xed_document_loader_loading (XED_DOCUMENT_LOADER (gvloader),
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
gvloader->priv->cancellable = g_cancellable_new ();
|
||||
async = async_data_new (gvloader);
|
||||
|
||||
open_async_read (async);
|
||||
}
|
||||
|
||||
static goffset
|
||||
xed_gio_document_loader_get_bytes_read (XedDocumentLoader *loader)
|
||||
{
|
||||
return XED_GIO_DOCUMENT_LOADER (loader)->priv->bytes_read;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xed_gio_document_loader_cancel (XedDocumentLoader *loader)
|
||||
{
|
||||
XedGioDocumentLoader *gvloader = XED_GIO_DOCUMENT_LOADER (loader);
|
||||
|
||||
if (gvloader->priv->cancellable == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_cancellable_cancel (gvloader->priv->cancellable);
|
||||
|
||||
g_set_error (&gvloader->priv->error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_CANCELLED,
|
||||
"Operation cancelled");
|
||||
|
||||
remote_load_completed_or_failed (gvloader, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
79
xed/xed-gio-document-loader.h
Normal file
79
xed/xed-gio-document-loader.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* xed-gio-document-loader.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
* Copyright (C) 2007 - Paolo Maggi, Steve Frécinaux
|
||||
* Copyright (C) 2008 - Jesse van den Kieboom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005-2008. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_GIO_DOCUMENT_LOADER_H__
|
||||
#define __XED_GIO_DOCUMENT_LOADER_H__
|
||||
|
||||
#include <xed/xed-document.h>
|
||||
#include "xed-document-loader.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_GIO_DOCUMENT_LOADER (xed_gio_document_loader_get_type())
|
||||
#define XED_GIO_DOCUMENT_LOADER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_GIO_DOCUMENT_LOADER, XedGioDocumentLoader))
|
||||
#define XED_GIO_DOCUMENT_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_GIO_DOCUMENT_LOADER, XedGioDocumentLoaderClass))
|
||||
#define XED_IS_GIO_DOCUMENT_LOADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_GIO_DOCUMENT_LOADER))
|
||||
#define XED_IS_GIO_DOCUMENT_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_GIO_DOCUMENT_LOADER))
|
||||
#define XED_GIO_DOCUMENT_LOADER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_GIO_DOCUMENT_LOADER, XedGioDocumentLoaderClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedGioDocumentLoaderPrivate XedGioDocumentLoaderPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedGioDocumentLoader XedGioDocumentLoader;
|
||||
|
||||
struct _XedGioDocumentLoader
|
||||
{
|
||||
XedDocumentLoader loader;
|
||||
|
||||
/*< private > */
|
||||
XedGioDocumentLoaderPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef XedDocumentLoaderClass XedGioDocumentLoaderClass;
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_gio_document_loader_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_GIO_DOCUMENT_LOADER_H__ */
|
||||
775
xed/xed-gio-document-saver.c
Normal file
775
xed/xed-gio-document-saver.c
Normal file
@@ -0,0 +1,775 @@
|
||||
/*
|
||||
* xed-gio-document-saver.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005-2006 - Paolo Borelli and Paolo Maggi
|
||||
* Copyright (C) 2007 - Paolo Borelli, Paolo Maggi, Steve Frécinaux
|
||||
* Copyright (C) 2008 - Jesse van den Kieboom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005-2006. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib.h>
|
||||
#include <gio/gio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "xed-gio-document-saver.h"
|
||||
#include "xed-document-input-stream.h"
|
||||
#include "xed-debug.h"
|
||||
|
||||
#define WRITE_CHUNK_SIZE 8192
|
||||
|
||||
typedef struct
|
||||
{
|
||||
XedGioDocumentSaver *saver;
|
||||
gchar buffer[WRITE_CHUNK_SIZE];
|
||||
GCancellable *cancellable;
|
||||
gboolean tried_mount;
|
||||
gssize written;
|
||||
gssize read;
|
||||
GError *error;
|
||||
} AsyncData;
|
||||
|
||||
#define REMOTE_QUERY_ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \
|
||||
G_FILE_ATTRIBUTE_TIME_MODIFIED
|
||||
|
||||
#define XED_GIO_DOCUMENT_SAVER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
|
||||
XED_TYPE_GIO_DOCUMENT_SAVER, \
|
||||
XedGioDocumentSaverPrivate))
|
||||
|
||||
static void xed_gio_document_saver_save (XedDocumentSaver *saver,
|
||||
GTimeVal *old_mtime);
|
||||
static goffset xed_gio_document_saver_get_file_size (XedDocumentSaver *saver);
|
||||
static goffset xed_gio_document_saver_get_bytes_written (XedDocumentSaver *saver);
|
||||
|
||||
|
||||
static void check_modified_async (AsyncData *async);
|
||||
|
||||
struct _XedGioDocumentSaverPrivate
|
||||
{
|
||||
GTimeVal old_mtime;
|
||||
|
||||
goffset size;
|
||||
goffset bytes_written;
|
||||
|
||||
GFile *gfile;
|
||||
GCancellable *cancellable;
|
||||
GOutputStream *stream;
|
||||
GInputStream *input;
|
||||
|
||||
GError *error;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(XedGioDocumentSaver, xed_gio_document_saver, XED_TYPE_DOCUMENT_SAVER)
|
||||
|
||||
static void
|
||||
xed_gio_document_saver_dispose (GObject *object)
|
||||
{
|
||||
XedGioDocumentSaverPrivate *priv = XED_GIO_DOCUMENT_SAVER (object)->priv;
|
||||
|
||||
if (priv->cancellable != NULL)
|
||||
{
|
||||
g_cancellable_cancel (priv->cancellable);
|
||||
g_object_unref (priv->cancellable);
|
||||
priv->cancellable = NULL;
|
||||
}
|
||||
|
||||
if (priv->gfile != NULL)
|
||||
{
|
||||
g_object_unref (priv->gfile);
|
||||
priv->gfile = NULL;
|
||||
}
|
||||
|
||||
if (priv->error != NULL)
|
||||
{
|
||||
g_error_free (priv->error);
|
||||
priv->error = NULL;
|
||||
}
|
||||
|
||||
if (priv->stream != NULL)
|
||||
{
|
||||
g_object_unref (priv->stream);
|
||||
priv->stream = NULL;
|
||||
}
|
||||
|
||||
if (priv->input != NULL)
|
||||
{
|
||||
g_object_unref (priv->input);
|
||||
priv->input = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (xed_gio_document_saver_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static AsyncData *
|
||||
async_data_new (XedGioDocumentSaver *gvsaver)
|
||||
{
|
||||
AsyncData *async;
|
||||
|
||||
async = g_slice_new (AsyncData);
|
||||
async->saver = gvsaver;
|
||||
async->cancellable = g_object_ref (gvsaver->priv->cancellable);
|
||||
|
||||
async->tried_mount = FALSE;
|
||||
async->written = 0;
|
||||
async->read = 0;
|
||||
|
||||
async->error = NULL;
|
||||
|
||||
return async;
|
||||
}
|
||||
|
||||
static void
|
||||
async_data_free (AsyncData *async)
|
||||
{
|
||||
g_object_unref (async->cancellable);
|
||||
|
||||
if (async->error)
|
||||
{
|
||||
g_error_free (async->error);
|
||||
}
|
||||
|
||||
g_slice_free (AsyncData, async);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_gio_document_saver_class_init (XedGioDocumentSaverClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
XedDocumentSaverClass *saver_class = XED_DOCUMENT_SAVER_CLASS (klass);
|
||||
|
||||
object_class->dispose = xed_gio_document_saver_dispose;
|
||||
|
||||
saver_class->save = xed_gio_document_saver_save;
|
||||
saver_class->get_file_size = xed_gio_document_saver_get_file_size;
|
||||
saver_class->get_bytes_written = xed_gio_document_saver_get_bytes_written;
|
||||
|
||||
g_type_class_add_private (object_class, sizeof(XedGioDocumentSaverPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
xed_gio_document_saver_init (XedGioDocumentSaver *gvsaver)
|
||||
{
|
||||
gvsaver->priv = XED_GIO_DOCUMENT_SAVER_GET_PRIVATE (gvsaver);
|
||||
|
||||
gvsaver->priv->cancellable = g_cancellable_new ();
|
||||
gvsaver->priv->error = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
remote_save_completed_or_failed (XedGioDocumentSaver *gvsaver,
|
||||
AsyncData *async)
|
||||
{
|
||||
xed_document_saver_saving (XED_DOCUMENT_SAVER (gvsaver),
|
||||
TRUE,
|
||||
gvsaver->priv->error);
|
||||
|
||||
if (async)
|
||||
async_data_free (async);
|
||||
}
|
||||
|
||||
static void
|
||||
async_failed (AsyncData *async,
|
||||
GError *error)
|
||||
{
|
||||
g_propagate_error (&async->saver->priv->error, error);
|
||||
remote_save_completed_or_failed (async->saver, async);
|
||||
}
|
||||
|
||||
/* BEGIN NOTE:
|
||||
*
|
||||
* This fixes an issue in GOutputStream that applies the atomic replace
|
||||
* save strategy. The stream moves the written file to the original file
|
||||
* when the stream is closed. However, there is no way currently to tell
|
||||
* the stream that the save should be aborted (there could be a
|
||||
* conversion error). The patch explicitly closes the output stream
|
||||
* in all these cases with a GCancellable in the cancelled state, causing
|
||||
* the output stream to close, but not move the file. This makes use
|
||||
* of an implementation detail in the local gio file stream and should be
|
||||
* properly fixed by adding the appropriate API in gio. Until then, at least
|
||||
* we prevent data corruption for now.
|
||||
*
|
||||
* Relevant bug reports:
|
||||
*
|
||||
* Bug 615110 - write file ignore encoding errors (xed)
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=615110
|
||||
*
|
||||
* Bug 602412 - g_file_replace does not restore original file when there is
|
||||
* errors while writing (glib/gio)
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=602412
|
||||
*/
|
||||
static void
|
||||
cancel_output_stream_ready_cb (GOutputStream *stream,
|
||||
GAsyncResult *result,
|
||||
AsyncData *async)
|
||||
{
|
||||
GError *error;
|
||||
|
||||
g_output_stream_close_finish (stream, result, NULL);
|
||||
|
||||
/* check cancelled state manually */
|
||||
if (g_cancellable_is_cancelled (async->cancellable) || async->error == NULL)
|
||||
{
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
error = async->error;
|
||||
async->error = NULL;
|
||||
|
||||
async_failed (async, error);
|
||||
}
|
||||
|
||||
static void
|
||||
cancel_output_stream (AsyncData *async)
|
||||
{
|
||||
GCancellable *cancellable;
|
||||
|
||||
xed_debug_message (DEBUG_SAVER, "Cancel output stream");
|
||||
|
||||
cancellable = g_cancellable_new ();
|
||||
g_cancellable_cancel (cancellable);
|
||||
|
||||
g_output_stream_close_async (async->saver->priv->stream,
|
||||
G_PRIORITY_HIGH,
|
||||
cancellable,
|
||||
(GAsyncReadyCallback)cancel_output_stream_ready_cb,
|
||||
async);
|
||||
|
||||
g_object_unref (cancellable);
|
||||
}
|
||||
|
||||
static void
|
||||
cancel_output_stream_and_fail (AsyncData *async,
|
||||
GError *error)
|
||||
{
|
||||
|
||||
xed_debug_message (DEBUG_SAVER, "Cancel output stream and fail");
|
||||
|
||||
g_propagate_error (&async->error, error);
|
||||
cancel_output_stream (async);
|
||||
}
|
||||
|
||||
/*
|
||||
* END NOTE
|
||||
*/
|
||||
|
||||
static void
|
||||
remote_get_info_cb (GFile *source,
|
||||
GAsyncResult *res,
|
||||
AsyncData *async)
|
||||
{
|
||||
XedGioDocumentSaver *saver;
|
||||
GFileInfo *info;
|
||||
GError *error = NULL;
|
||||
|
||||
xed_debug (DEBUG_SAVER);
|
||||
|
||||
/* check cancelled state manually */
|
||||
if (g_cancellable_is_cancelled (async->cancellable))
|
||||
{
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
saver = async->saver;
|
||||
|
||||
xed_debug_message (DEBUG_SAVER, "Finished query info on file");
|
||||
info = g_file_query_info_finish (source, res, &error);
|
||||
|
||||
if (info != NULL)
|
||||
{
|
||||
if (XED_DOCUMENT_SAVER (saver)->info != NULL)
|
||||
g_object_unref (XED_DOCUMENT_SAVER (saver)->info);
|
||||
|
||||
XED_DOCUMENT_SAVER (saver)->info = info;
|
||||
}
|
||||
else
|
||||
{
|
||||
xed_debug_message (DEBUG_SAVER, "Query info failed: %s", error->message);
|
||||
g_propagate_error (&saver->priv->error, error);
|
||||
}
|
||||
|
||||
remote_save_completed_or_failed (saver, async);
|
||||
}
|
||||
|
||||
static void
|
||||
close_async_ready_get_info_cb (GOutputStream *stream,
|
||||
GAsyncResult *res,
|
||||
AsyncData *async)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
xed_debug (DEBUG_SAVER);
|
||||
|
||||
/* check cancelled state manually */
|
||||
if (g_cancellable_is_cancelled (async->cancellable))
|
||||
{
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
xed_debug_message (DEBUG_SAVER, "Finished closing stream");
|
||||
|
||||
if (!g_output_stream_close_finish (stream, res, &error))
|
||||
{
|
||||
xed_debug_message (DEBUG_SAVER, "Closing stream error: %s", error->message);
|
||||
|
||||
async_failed (async, error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the file info: note we cannot use
|
||||
* g_file_output_stream_query_info_async since it is not able to get the
|
||||
* content type etc, beside it is not supported by gvfs.
|
||||
* I'm not sure this is actually necessary, can't we just use
|
||||
* g_content_type_guess (since we have the file name and the data)
|
||||
*/
|
||||
xed_debug_message (DEBUG_SAVER, "Query info on file");
|
||||
g_file_query_info_async (async->saver->priv->gfile,
|
||||
REMOTE_QUERY_ATTRIBUTES,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
G_PRIORITY_HIGH,
|
||||
async->cancellable,
|
||||
(GAsyncReadyCallback) remote_get_info_cb,
|
||||
async);
|
||||
}
|
||||
|
||||
static void
|
||||
write_complete (AsyncData *async)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
/* first we close the input stream */
|
||||
xed_debug_message (DEBUG_SAVER, "Close input stream");
|
||||
if (!g_input_stream_close (async->saver->priv->input,
|
||||
async->cancellable, &error))
|
||||
{
|
||||
xed_debug_message (DEBUG_SAVER, "Closing input stream error: %s", error->message);
|
||||
cancel_output_stream_and_fail (async, error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* now we close the output stream */
|
||||
xed_debug_message (DEBUG_SAVER, "Close output stream");
|
||||
g_output_stream_close_async (async->saver->priv->stream,
|
||||
G_PRIORITY_HIGH,
|
||||
async->cancellable,
|
||||
(GAsyncReadyCallback)close_async_ready_get_info_cb,
|
||||
async);
|
||||
}
|
||||
|
||||
/* prototype, because they call each other... isn't C lovely */
|
||||
static void read_file_chunk (AsyncData *async);
|
||||
static void write_file_chunk (AsyncData *async);
|
||||
|
||||
static void
|
||||
async_write_cb (GOutputStream *stream,
|
||||
GAsyncResult *res,
|
||||
AsyncData *async)
|
||||
{
|
||||
XedGioDocumentSaver *gvsaver;
|
||||
gssize bytes_written;
|
||||
GError *error = NULL;
|
||||
|
||||
xed_debug (DEBUG_SAVER);
|
||||
|
||||
/* Check cancelled state manually */
|
||||
if (g_cancellable_is_cancelled (async->cancellable))
|
||||
{
|
||||
cancel_output_stream (async);
|
||||
return;
|
||||
}
|
||||
|
||||
bytes_written = g_output_stream_write_finish (stream, res, &error);
|
||||
|
||||
xed_debug_message (DEBUG_SAVER, "Written: %" G_GSSIZE_FORMAT, bytes_written);
|
||||
|
||||
if (bytes_written == -1)
|
||||
{
|
||||
xed_debug_message (DEBUG_SAVER, "Write error: %s", error->message);
|
||||
cancel_output_stream_and_fail (async, error);
|
||||
return;
|
||||
}
|
||||
|
||||
gvsaver = async->saver;
|
||||
async->written += bytes_written;
|
||||
|
||||
/* write again */
|
||||
if (async->written != async->read)
|
||||
{
|
||||
write_file_chunk (async);
|
||||
return;
|
||||
}
|
||||
|
||||
/* note that this signal blocks the write... check if it isn't
|
||||
* a performance problem
|
||||
*/
|
||||
xed_document_saver_saving (XED_DOCUMENT_SAVER (gvsaver),
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
read_file_chunk (async);
|
||||
}
|
||||
|
||||
static void
|
||||
write_file_chunk (AsyncData *async)
|
||||
{
|
||||
XedGioDocumentSaver *gvsaver;
|
||||
|
||||
xed_debug (DEBUG_SAVER);
|
||||
|
||||
gvsaver = async->saver;
|
||||
|
||||
g_output_stream_write_async (G_OUTPUT_STREAM (gvsaver->priv->stream),
|
||||
async->buffer + async->written,
|
||||
async->read - async->written,
|
||||
G_PRIORITY_HIGH,
|
||||
async->cancellable,
|
||||
(GAsyncReadyCallback) async_write_cb,
|
||||
async);
|
||||
}
|
||||
|
||||
static void
|
||||
read_file_chunk (AsyncData *async)
|
||||
{
|
||||
XedGioDocumentSaver *gvsaver;
|
||||
XedDocumentInputStream *dstream;
|
||||
GError *error = NULL;
|
||||
|
||||
xed_debug (DEBUG_SAVER);
|
||||
|
||||
gvsaver = async->saver;
|
||||
async->written = 0;
|
||||
|
||||
/* we use sync methods on doc stream since it is in memory. Using async
|
||||
would be racy and we can endup with invalidated iters */
|
||||
async->read = g_input_stream_read (gvsaver->priv->input,
|
||||
async->buffer,
|
||||
WRITE_CHUNK_SIZE,
|
||||
async->cancellable,
|
||||
&error);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
cancel_output_stream_and_fail (async, error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if we finished reading and writing */
|
||||
if (async->read == 0)
|
||||
{
|
||||
write_complete (async);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get how many chars have been read */
|
||||
dstream = XED_DOCUMENT_INPUT_STREAM (gvsaver->priv->input);
|
||||
gvsaver->priv->bytes_written = xed_document_input_stream_tell (dstream);
|
||||
|
||||
write_file_chunk (async);
|
||||
}
|
||||
|
||||
static void
|
||||
async_replace_ready_callback (GFile *source,
|
||||
GAsyncResult *res,
|
||||
AsyncData *async)
|
||||
{
|
||||
XedGioDocumentSaver *gvsaver;
|
||||
XedDocumentSaver *saver;
|
||||
GCharsetConverter *converter;
|
||||
GFileOutputStream *file_stream;
|
||||
GError *error = NULL;
|
||||
|
||||
xed_debug (DEBUG_SAVER);
|
||||
|
||||
/* Check cancelled state manually */
|
||||
if (g_cancellable_is_cancelled (async->cancellable))
|
||||
{
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
gvsaver = async->saver;
|
||||
saver = XED_DOCUMENT_SAVER (gvsaver);
|
||||
file_stream = g_file_replace_finish (source, res, &error);
|
||||
|
||||
/* handle any error that might occur */
|
||||
if (!file_stream)
|
||||
{
|
||||
xed_debug_message (DEBUG_SAVER, "Opening file failed: %s", error->message);
|
||||
async_failed (async, error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: manage converter error? */
|
||||
xed_debug_message (DEBUG_SAVER, "Encoding charset: %s",
|
||||
xed_encoding_get_charset (saver->encoding));
|
||||
|
||||
if (saver->encoding != xed_encoding_get_utf8 ())
|
||||
{
|
||||
converter = g_charset_converter_new (xed_encoding_get_charset (saver->encoding),
|
||||
"UTF-8",
|
||||
NULL);
|
||||
gvsaver->priv->stream = g_converter_output_stream_new (G_OUTPUT_STREAM (file_stream),
|
||||
G_CONVERTER (converter));
|
||||
|
||||
g_object_unref (file_stream);
|
||||
g_object_unref (converter);
|
||||
}
|
||||
else
|
||||
{
|
||||
gvsaver->priv->stream = G_OUTPUT_STREAM (file_stream);
|
||||
}
|
||||
|
||||
gvsaver->priv->input = xed_document_input_stream_new (GTK_TEXT_BUFFER (saver->document),
|
||||
saver->newline_type);
|
||||
|
||||
gvsaver->priv->size = xed_document_input_stream_get_total_size (XED_DOCUMENT_INPUT_STREAM (gvsaver->priv->input));
|
||||
|
||||
read_file_chunk (async);
|
||||
}
|
||||
|
||||
static void
|
||||
begin_write (AsyncData *async)
|
||||
{
|
||||
XedGioDocumentSaver *gvsaver;
|
||||
XedDocumentSaver *saver;
|
||||
gboolean backup;
|
||||
|
||||
xed_debug_message (DEBUG_SAVER, "Start replacing file contents");
|
||||
|
||||
/* For remote files we simply use g_file_replace_async. There is no
|
||||
* backup as of yet
|
||||
*/
|
||||
gvsaver = async->saver;
|
||||
saver = XED_DOCUMENT_SAVER (gvsaver);
|
||||
|
||||
/* Do not make backups for remote files so they do not clutter remote systems */
|
||||
backup = (saver->keep_backup && xed_document_is_local (saver->document));
|
||||
|
||||
xed_debug_message (DEBUG_SAVER, "File contents size: %" G_GINT64_FORMAT, gvsaver->priv->size);
|
||||
xed_debug_message (DEBUG_SAVER, "Calling replace_async");
|
||||
xed_debug_message (DEBUG_SAVER, backup ? "Keep backup" : "Discard backup");
|
||||
|
||||
g_file_replace_async (gvsaver->priv->gfile,
|
||||
NULL,
|
||||
backup,
|
||||
G_FILE_CREATE_NONE,
|
||||
G_PRIORITY_HIGH,
|
||||
async->cancellable,
|
||||
(GAsyncReadyCallback) async_replace_ready_callback,
|
||||
async);
|
||||
}
|
||||
|
||||
static void
|
||||
mount_ready_callback (GFile *file,
|
||||
GAsyncResult *res,
|
||||
AsyncData *async)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gboolean mounted;
|
||||
|
||||
xed_debug (DEBUG_SAVER);
|
||||
|
||||
/* manual check for cancelled state */
|
||||
if (g_cancellable_is_cancelled (async->cancellable))
|
||||
{
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
mounted = g_file_mount_enclosing_volume_finish (file, res, &error);
|
||||
|
||||
if (!mounted)
|
||||
{
|
||||
async_failed (async, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* try again to get the modified state */
|
||||
check_modified_async (async);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
recover_not_mounted (AsyncData *async)
|
||||
{
|
||||
XedDocument *doc;
|
||||
GMountOperation *mount_operation;
|
||||
|
||||
xed_debug (DEBUG_LOADER);
|
||||
|
||||
doc = xed_document_saver_get_document (XED_DOCUMENT_SAVER (async->saver));
|
||||
mount_operation = _xed_document_create_mount_operation (doc);
|
||||
|
||||
async->tried_mount = TRUE;
|
||||
g_file_mount_enclosing_volume (async->saver->priv->gfile,
|
||||
G_MOUNT_MOUNT_NONE,
|
||||
mount_operation,
|
||||
async->cancellable,
|
||||
(GAsyncReadyCallback) mount_ready_callback,
|
||||
async);
|
||||
|
||||
g_object_unref (mount_operation);
|
||||
}
|
||||
|
||||
static void
|
||||
check_modification_callback (GFile *source,
|
||||
GAsyncResult *res,
|
||||
AsyncData *async)
|
||||
{
|
||||
XedGioDocumentSaver *gvsaver;
|
||||
GError *error = NULL;
|
||||
GFileInfo *info;
|
||||
|
||||
xed_debug (DEBUG_SAVER);
|
||||
|
||||
/* manually check cancelled state */
|
||||
if (g_cancellable_is_cancelled (async->cancellable))
|
||||
{
|
||||
async_data_free (async);
|
||||
return;
|
||||
}
|
||||
|
||||
gvsaver = async->saver;
|
||||
info = g_file_query_info_finish (source, res, &error);
|
||||
if (info == NULL)
|
||||
{
|
||||
if (error->code == G_IO_ERROR_NOT_MOUNTED && !async->tried_mount)
|
||||
{
|
||||
recover_not_mounted (async);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* it's perfectly fine if the file doesn't exist yet */
|
||||
if (error->code != G_IO_ERROR_NOT_FOUND)
|
||||
{
|
||||
xed_debug_message (DEBUG_SAVER, "Error getting modification: %s", error->message);
|
||||
|
||||
async_failed (async, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if the mtime is > what we know about it (if we have it) */
|
||||
if (info != NULL && g_file_info_has_attribute (info,
|
||||
G_FILE_ATTRIBUTE_TIME_MODIFIED))
|
||||
{
|
||||
GTimeVal mtime;
|
||||
GTimeVal old_mtime;
|
||||
|
||||
g_file_info_get_modification_time (info, &mtime);
|
||||
old_mtime = gvsaver->priv->old_mtime;
|
||||
|
||||
if ((old_mtime.tv_sec > 0 || old_mtime.tv_usec > 0) &&
|
||||
(mtime.tv_sec != old_mtime.tv_sec || mtime.tv_usec != old_mtime.tv_usec) &&
|
||||
(XED_DOCUMENT_SAVER (gvsaver)->flags & XED_DOCUMENT_SAVE_IGNORE_MTIME) == 0)
|
||||
{
|
||||
xed_debug_message (DEBUG_SAVER, "File is externally modified");
|
||||
g_set_error (&gvsaver->priv->error,
|
||||
XED_DOCUMENT_ERROR,
|
||||
XED_DOCUMENT_ERROR_EXTERNALLY_MODIFIED,
|
||||
"Externally modified");
|
||||
|
||||
remote_save_completed_or_failed (gvsaver, async);
|
||||
g_object_unref (info);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (info != NULL)
|
||||
g_object_unref (info);
|
||||
|
||||
/* modification check passed, start write */
|
||||
begin_write (async);
|
||||
}
|
||||
|
||||
static void
|
||||
check_modified_async (AsyncData *async)
|
||||
{
|
||||
xed_debug_message (DEBUG_SAVER, "Check externally modified");
|
||||
|
||||
g_file_query_info_async (async->saver->priv->gfile,
|
||||
G_FILE_ATTRIBUTE_TIME_MODIFIED,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
G_PRIORITY_HIGH,
|
||||
async->cancellable,
|
||||
(GAsyncReadyCallback) check_modification_callback,
|
||||
async);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
save_remote_file_real (XedGioDocumentSaver *gvsaver)
|
||||
{
|
||||
AsyncData *async;
|
||||
|
||||
xed_debug_message (DEBUG_SAVER, "Starting gio save");
|
||||
|
||||
/* First find out if the file is modified externally. This requires
|
||||
* a stat, but I don't think we can do this any other way
|
||||
*/
|
||||
async = async_data_new (gvsaver);
|
||||
|
||||
check_modified_async (async);
|
||||
|
||||
/* return false to stop timeout */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
xed_gio_document_saver_save (XedDocumentSaver *saver,
|
||||
GTimeVal *old_mtime)
|
||||
{
|
||||
XedGioDocumentSaver *gvsaver = XED_GIO_DOCUMENT_SAVER (saver);
|
||||
|
||||
gvsaver->priv->old_mtime = *old_mtime;
|
||||
gvsaver->priv->gfile = g_file_new_for_uri (saver->uri);
|
||||
|
||||
/* saving start */
|
||||
xed_document_saver_saving (saver, FALSE, NULL);
|
||||
|
||||
g_timeout_add_full (G_PRIORITY_HIGH,
|
||||
0,
|
||||
(GSourceFunc) save_remote_file_real,
|
||||
gvsaver,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static goffset
|
||||
xed_gio_document_saver_get_file_size (XedDocumentSaver *saver)
|
||||
{
|
||||
return XED_GIO_DOCUMENT_SAVER (saver)->priv->size;
|
||||
}
|
||||
|
||||
static goffset
|
||||
xed_gio_document_saver_get_bytes_written (XedDocumentSaver *saver)
|
||||
{
|
||||
return XED_GIO_DOCUMENT_SAVER (saver)->priv->bytes_written;
|
||||
}
|
||||
76
xed/xed-gio-document-saver.h
Normal file
76
xed/xed-gio-document-saver.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* xed-gio-document-saver.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
* Copyrhing (C) 2007 - Paolo Maggi, Steve Frécinaux
|
||||
* Copyright (C) 2008 - Jesse van den Kieboom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005-2007. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*/
|
||||
|
||||
#ifndef __XED_GIO_DOCUMENT_SAVER_H__
|
||||
#define __XED_GIO_DOCUMENT_SAVER_H__
|
||||
|
||||
#include <xed/xed-document-saver.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_GIO_DOCUMENT_SAVER (xed_gio_document_saver_get_type())
|
||||
#define XED_GIO_DOCUMENT_SAVER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_GIO_DOCUMENT_SAVER, XedGioDocumentSaver))
|
||||
#define XED_GIO_DOCUMENT_SAVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_GIO_DOCUMENT_SAVER, XedGioDocumentSaverClass))
|
||||
#define XED_IS_GIO_DOCUMENT_SAVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_GIO_DOCUMENT_SAVER))
|
||||
#define XED_IS_GIO_DOCUMENT_SAVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_GIO_DOCUMENT_SAVER))
|
||||
#define XED_GIO_DOCUMENT_SAVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_GIO_DOCUMENT_SAVER, XedGioDocumentSaverClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedGioDocumentSaverPrivate XedGioDocumentSaverPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedGioDocumentSaver XedGioDocumentSaver;
|
||||
|
||||
struct _XedGioDocumentSaver
|
||||
{
|
||||
XedDocumentSaver saver;
|
||||
|
||||
/*< private > */
|
||||
XedGioDocumentSaverPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef XedDocumentSaverClass XedGioDocumentSaverClass;
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_gio_document_saver_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_GIO_DOCUMENT_SAVER_H__ */
|
||||
99
xed/xed-help.c
Normal file
99
xed/xed-help.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* xed-help.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "xed-help.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <string.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
gboolean
|
||||
xed_help_display (GtkWindow *parent,
|
||||
const gchar *name, /* "xed" if NULL */
|
||||
const gchar *link_id)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gboolean ret;
|
||||
gchar *link;
|
||||
|
||||
g_return_val_if_fail ((parent == NULL) || GTK_IS_WINDOW (parent), FALSE);
|
||||
|
||||
if (name == NULL)
|
||||
name = "xed";
|
||||
else if (strcmp (name, "xed.xml") == 0)
|
||||
{
|
||||
g_warning ("%s: Using \"xed.xml\" for the help name is deprecated, use \"xed\" or simply NULL instead", G_STRFUNC);
|
||||
|
||||
name = "xed";
|
||||
}
|
||||
|
||||
if (link_id)
|
||||
link = g_strdup_printf ("help:%s/%s", name, link_id);
|
||||
else
|
||||
link = g_strdup_printf ("help:%s", name);
|
||||
|
||||
ret = gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (parent)),
|
||||
link,
|
||||
GDK_CURRENT_TIME,
|
||||
&error);
|
||||
|
||||
g_free (link);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = gtk_message_dialog_new (parent,
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
_("There was an error displaying the help."));
|
||||
|
||||
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
|
||||
"%s", error->message);
|
||||
|
||||
g_signal_connect (G_OBJECT (dialog),
|
||||
"response",
|
||||
G_CALLBACK (gtk_widget_destroy),
|
||||
NULL);
|
||||
|
||||
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
44
xed/xed-help.h
Normal file
44
xed/xed-help.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* xed-help.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_HELP_H__
|
||||
#define __XED_HELP_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean xed_help_display (GtkWindow *parent,
|
||||
const gchar *name, /* "xed" if NULL */
|
||||
const gchar *link_id);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_HELP_H__ */
|
||||
599
xed/xed-history-entry.c
Normal file
599
xed/xed-history-entry.c
Normal file
@@ -0,0 +1,599 @@
|
||||
/*
|
||||
* xed-history-entry.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2006 - Paolo Borelli
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2006. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "xed-history-entry.h"
|
||||
#include "xed-prefs-manager.h"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_HISTORY_ID,
|
||||
PROP_HISTORY_LENGTH
|
||||
};
|
||||
|
||||
#define MIN_ITEM_LEN 3
|
||||
|
||||
#define XED_HISTORY_ENTRY_HISTORY_LENGTH_DEFAULT 10
|
||||
|
||||
#define XED_HISTORY_ENTRY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
|
||||
XED_TYPE_HISTORY_ENTRY, \
|
||||
XedHistoryEntryPrivate))
|
||||
|
||||
struct _XedHistoryEntryPrivate
|
||||
{
|
||||
gchar *history_id;
|
||||
guint history_length;
|
||||
|
||||
GtkEntryCompletion *completion;
|
||||
|
||||
GSettings *settings;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(XedHistoryEntry, xed_history_entry, GTK_TYPE_COMBO_BOX_TEXT)
|
||||
|
||||
static void
|
||||
xed_history_entry_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *spec)
|
||||
{
|
||||
XedHistoryEntry *entry;
|
||||
|
||||
g_return_if_fail (XED_IS_HISTORY_ENTRY (object));
|
||||
|
||||
entry = XED_HISTORY_ENTRY (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_HISTORY_ID:
|
||||
entry->priv->history_id = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_HISTORY_LENGTH:
|
||||
xed_history_entry_set_history_length (entry,
|
||||
g_value_get_uint (value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_history_entry_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *spec)
|
||||
{
|
||||
XedHistoryEntryPrivate *priv;
|
||||
|
||||
g_return_if_fail (XED_IS_HISTORY_ENTRY (object));
|
||||
|
||||
priv = XED_HISTORY_ENTRY (object)->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_HISTORY_ID:
|
||||
g_value_set_string (value, priv->history_id);
|
||||
break;
|
||||
case PROP_HISTORY_LENGTH:
|
||||
g_value_set_uint (value, priv->history_length);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, spec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_history_entry_dispose (GObject *object)
|
||||
{
|
||||
xed_history_entry_set_enable_completion (XED_HISTORY_ENTRY (object),
|
||||
FALSE);
|
||||
|
||||
G_OBJECT_CLASS (xed_history_entry_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_history_entry_finalize (GObject *object)
|
||||
{
|
||||
XedHistoryEntryPrivate *priv;
|
||||
|
||||
priv = XED_HISTORY_ENTRY (object)->priv;
|
||||
|
||||
g_free (priv->history_id);
|
||||
|
||||
if (priv->settings != NULL)
|
||||
{
|
||||
g_object_unref (G_OBJECT (priv->settings));
|
||||
priv->settings = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (xed_history_entry_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_history_entry_class_init (XedHistoryEntryClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = xed_history_entry_set_property;
|
||||
object_class->get_property = xed_history_entry_get_property;
|
||||
object_class->finalize = xed_history_entry_finalize;
|
||||
object_class->dispose = xed_history_entry_dispose;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_HISTORY_ID,
|
||||
g_param_spec_string ("history-id",
|
||||
"History ID",
|
||||
"History ID",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_HISTORY_LENGTH,
|
||||
g_param_spec_uint ("history-length",
|
||||
"Max History Length",
|
||||
"Max History Length",
|
||||
0,
|
||||
G_MAXUINT,
|
||||
XED_HISTORY_ENTRY_HISTORY_LENGTH_DEFAULT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/* TODO: Add enable-completion property */
|
||||
|
||||
g_type_class_add_private (object_class, sizeof(XedHistoryEntryPrivate));
|
||||
}
|
||||
|
||||
static GtkListStore *
|
||||
get_history_store (XedHistoryEntry *entry)
|
||||
{
|
||||
GtkTreeModel *store;
|
||||
|
||||
store = gtk_combo_box_get_model (GTK_COMBO_BOX (entry));
|
||||
g_return_val_if_fail (GTK_IS_LIST_STORE (store), NULL);
|
||||
|
||||
return (GtkListStore *) store;
|
||||
}
|
||||
|
||||
static GSList *
|
||||
get_history_list (XedHistoryEntry *entry)
|
||||
{
|
||||
GtkListStore *store;
|
||||
GtkTreeIter iter;
|
||||
gboolean valid;
|
||||
GSList *list = NULL;
|
||||
|
||||
store = get_history_store (entry);
|
||||
|
||||
valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store),
|
||||
&iter);
|
||||
|
||||
while (valid)
|
||||
{
|
||||
gchar *str;
|
||||
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (store),
|
||||
&iter,
|
||||
0, &str,
|
||||
-1);
|
||||
|
||||
list = g_slist_prepend (list, str);
|
||||
|
||||
valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store),
|
||||
&iter);
|
||||
}
|
||||
|
||||
return g_slist_reverse (list);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_history_entry_save_history (XedHistoryEntry *entry)
|
||||
{
|
||||
GSList *settings_items;
|
||||
|
||||
g_return_if_fail (XED_IS_HISTORY_ENTRY (entry));
|
||||
|
||||
settings_items = get_history_list (entry);
|
||||
|
||||
xed_prefs_manager_set_gslist (entry->priv->settings,
|
||||
entry->priv->history_id,
|
||||
settings_items);
|
||||
|
||||
g_slist_foreach (settings_items, (GFunc) g_free, NULL);
|
||||
g_slist_free (settings_items);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
remove_item (GtkListStore *store,
|
||||
const gchar *text)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
|
||||
g_return_val_if_fail (text != NULL, FALSE);
|
||||
|
||||
if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
|
||||
return FALSE;
|
||||
|
||||
do
|
||||
{
|
||||
gchar *item_text;
|
||||
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (store),
|
||||
&iter,
|
||||
0,
|
||||
&item_text,
|
||||
-1);
|
||||
|
||||
if (item_text != NULL &&
|
||||
strcmp (item_text, text) == 0)
|
||||
{
|
||||
gtk_list_store_remove (store, &iter);
|
||||
g_free (item_text);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_free (item_text);
|
||||
|
||||
} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
clamp_list_store (GtkListStore *store,
|
||||
guint max)
|
||||
{
|
||||
GtkTreePath *path;
|
||||
GtkTreeIter iter;
|
||||
|
||||
/* -1 because TreePath counts from 0 */
|
||||
path = gtk_tree_path_new_from_indices (max - 1, -1);
|
||||
|
||||
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
if (!gtk_list_store_remove (store, &iter))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
insert_history_item (XedHistoryEntry *entry,
|
||||
const gchar *text,
|
||||
gboolean prepend)
|
||||
{
|
||||
GtkListStore *store;
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (g_utf8_strlen (text, -1) <= MIN_ITEM_LEN)
|
||||
return;
|
||||
|
||||
store = get_history_store (entry);
|
||||
|
||||
/* remove the text from the store if it was already
|
||||
* present. If it wasn't, clamp to max history - 1
|
||||
* before inserting the new row, otherwise appending
|
||||
* would not work */
|
||||
|
||||
if (!remove_item (store, text))
|
||||
clamp_list_store (store,
|
||||
entry->priv->history_length - 1);
|
||||
|
||||
if (prepend)
|
||||
gtk_list_store_insert (store, &iter, 0);
|
||||
else
|
||||
gtk_list_store_append (store, &iter);
|
||||
|
||||
gtk_list_store_set (store,
|
||||
&iter,
|
||||
0,
|
||||
text,
|
||||
-1);
|
||||
|
||||
xed_history_entry_save_history (entry);
|
||||
}
|
||||
|
||||
void
|
||||
xed_history_entry_prepend_text (XedHistoryEntry *entry,
|
||||
const gchar *text)
|
||||
{
|
||||
g_return_if_fail (XED_IS_HISTORY_ENTRY (entry));
|
||||
g_return_if_fail (text != NULL);
|
||||
|
||||
insert_history_item (entry, text, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
xed_history_entry_append_text (XedHistoryEntry *entry,
|
||||
const gchar *text)
|
||||
{
|
||||
g_return_if_fail (XED_IS_HISTORY_ENTRY (entry));
|
||||
g_return_if_fail (text != NULL);
|
||||
|
||||
insert_history_item (entry, text, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_history_entry_load_history (XedHistoryEntry *entry)
|
||||
{
|
||||
GSList *settings_items, *l;
|
||||
GtkListStore *store;
|
||||
GtkTreeIter iter;
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (XED_IS_HISTORY_ENTRY (entry));
|
||||
|
||||
store = get_history_store (entry);
|
||||
|
||||
settings_items = xed_prefs_manager_get_gslist (entry->priv->settings,
|
||||
entry->priv->history_id);
|
||||
|
||||
gtk_list_store_clear (store);
|
||||
|
||||
for (l = settings_items, i = 0;
|
||||
l != NULL && i < entry->priv->history_length;
|
||||
l = l->next, i++)
|
||||
{
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store,
|
||||
&iter,
|
||||
0,
|
||||
l->data,
|
||||
-1);
|
||||
}
|
||||
|
||||
g_slist_foreach (settings_items, (GFunc) g_free, NULL);
|
||||
g_slist_free (settings_items);
|
||||
}
|
||||
|
||||
void
|
||||
xed_history_entry_clear (XedHistoryEntry *entry)
|
||||
{
|
||||
GtkListStore *store;
|
||||
|
||||
g_return_if_fail (XED_IS_HISTORY_ENTRY (entry));
|
||||
|
||||
store = get_history_store (entry);
|
||||
gtk_list_store_clear (store);
|
||||
|
||||
xed_history_entry_save_history (entry);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_history_entry_init (XedHistoryEntry *entry)
|
||||
{
|
||||
XedHistoryEntryPrivate *priv;
|
||||
|
||||
priv = XED_HISTORY_ENTRY_GET_PRIVATE (entry);
|
||||
entry->priv = priv;
|
||||
|
||||
priv->history_id = NULL;
|
||||
priv->history_length = XED_HISTORY_ENTRY_HISTORY_LENGTH_DEFAULT;
|
||||
|
||||
priv->completion = NULL;
|
||||
|
||||
priv->settings = g_settings_new (XED_SCHEMA);
|
||||
}
|
||||
|
||||
void
|
||||
xed_history_entry_set_history_length (XedHistoryEntry *entry,
|
||||
guint history_length)
|
||||
{
|
||||
g_return_if_fail (XED_IS_HISTORY_ENTRY (entry));
|
||||
g_return_if_fail (history_length > 0);
|
||||
|
||||
entry->priv->history_length = history_length;
|
||||
|
||||
/* TODO: update if we currently have more items than max */
|
||||
}
|
||||
|
||||
guint
|
||||
xed_history_entry_get_history_length (XedHistoryEntry *entry)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_HISTORY_ENTRY (entry), 0);
|
||||
|
||||
return entry->priv->history_length;
|
||||
}
|
||||
|
||||
gchar *
|
||||
xed_history_entry_get_history_id (XedHistoryEntry *entry)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_HISTORY_ENTRY (entry), NULL);
|
||||
|
||||
return g_strdup (entry->priv->history_id);
|
||||
}
|
||||
|
||||
void
|
||||
xed_history_entry_set_enable_completion (XedHistoryEntry *entry,
|
||||
gboolean enable)
|
||||
{
|
||||
g_return_if_fail (XED_IS_HISTORY_ENTRY (entry));
|
||||
|
||||
if (enable)
|
||||
{
|
||||
if (entry->priv->completion != NULL)
|
||||
return;
|
||||
|
||||
entry->priv->completion = gtk_entry_completion_new ();
|
||||
gtk_entry_completion_set_model (entry->priv->completion,
|
||||
GTK_TREE_MODEL (get_history_store (entry)));
|
||||
|
||||
/* Use model column 0 as the text column */
|
||||
gtk_entry_completion_set_text_column (entry->priv->completion, 0);
|
||||
|
||||
gtk_entry_completion_set_minimum_key_length (entry->priv->completion,
|
||||
MIN_ITEM_LEN);
|
||||
|
||||
gtk_entry_completion_set_popup_completion (entry->priv->completion, FALSE);
|
||||
gtk_entry_completion_set_inline_completion (entry->priv->completion, TRUE);
|
||||
|
||||
/* Assign the completion to the entry */
|
||||
gtk_entry_set_completion (GTK_ENTRY (xed_history_entry_get_entry(entry)),
|
||||
entry->priv->completion);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (entry->priv->completion == NULL)
|
||||
return;
|
||||
|
||||
gtk_entry_set_completion (GTK_ENTRY (xed_history_entry_get_entry (entry)),
|
||||
NULL);
|
||||
|
||||
g_object_unref (entry->priv->completion);
|
||||
|
||||
entry->priv->completion = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_history_entry_get_enable_completion (XedHistoryEntry *entry)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_HISTORY_ENTRY (entry), FALSE);
|
||||
|
||||
return entry->priv->completion != NULL;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
xed_history_entry_new (const gchar *history_id,
|
||||
gboolean enable_completion)
|
||||
{
|
||||
GtkWidget *ret;
|
||||
GtkListStore *store;
|
||||
|
||||
g_return_val_if_fail (history_id != NULL, NULL);
|
||||
|
||||
/* Note that we are setting the model, so
|
||||
* user must be careful to always manipulate
|
||||
* data in the history through xed_history_entry_
|
||||
* functions.
|
||||
*/
|
||||
|
||||
store = gtk_list_store_new (1, G_TYPE_STRING);
|
||||
|
||||
ret = g_object_new (XED_TYPE_HISTORY_ENTRY,
|
||||
"history-id", history_id,
|
||||
"model", store,
|
||||
"has-entry", TRUE,
|
||||
"entry-text-column", 0,
|
||||
NULL);
|
||||
|
||||
g_object_unref (store);
|
||||
|
||||
/* loading has to happen after the model
|
||||
* has been set. However the model is not a
|
||||
* G_PARAM_CONSTRUCT property of GtkComboBox
|
||||
* so we cannot do this in the constructor.
|
||||
* For now we simply do here since this widget is
|
||||
* not bound to other programming languages.
|
||||
* A maybe better alternative is to override the
|
||||
* model property of combobox and mark CONTRUCT_ONLY.
|
||||
* This would also ensure that the model cannot be
|
||||
* set explicitely at a later time.
|
||||
*/
|
||||
xed_history_entry_load_history (XED_HISTORY_ENTRY (ret));
|
||||
|
||||
xed_history_entry_set_enable_completion (XED_HISTORY_ENTRY (ret),
|
||||
enable_completion);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to get the editable text entry internal widget.
|
||||
* I would prefer to not expose this implementation detail and
|
||||
* simply make the XedHistoryEntry widget implement the
|
||||
* GtkEditable interface. Unfortunately both GtkEditable and
|
||||
* GtkComboBox have a "changed" signal and I am not sure how to
|
||||
* handle the conflict.
|
||||
*/
|
||||
GtkWidget *
|
||||
xed_history_entry_get_entry (XedHistoryEntry *entry)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_HISTORY_ENTRY (entry), NULL);
|
||||
|
||||
return gtk_bin_get_child (GTK_BIN (entry));
|
||||
}
|
||||
|
||||
static void
|
||||
escape_cell_data_func (GtkTreeViewColumn *col,
|
||||
GtkCellRenderer *renderer,
|
||||
GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
XedHistoryEntryEscapeFunc escape_func)
|
||||
{
|
||||
gchar *str;
|
||||
gchar *escaped;
|
||||
|
||||
gtk_tree_model_get (model, iter, 0, &str, -1);
|
||||
escaped = escape_func (str);
|
||||
g_object_set (renderer, "text", escaped, NULL);
|
||||
|
||||
g_free (str);
|
||||
g_free (escaped);
|
||||
}
|
||||
|
||||
void
|
||||
xed_history_entry_set_escape_func (XedHistoryEntry *entry,
|
||||
XedHistoryEntryEscapeFunc escape_func)
|
||||
{
|
||||
GList *cells;
|
||||
|
||||
g_return_if_fail (XED_IS_HISTORY_ENTRY (entry));
|
||||
|
||||
cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (entry));
|
||||
|
||||
/* We only have one cell renderer */
|
||||
g_return_if_fail (cells->data != NULL && cells->next == NULL);
|
||||
|
||||
if (escape_func != NULL)
|
||||
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry),
|
||||
GTK_CELL_RENDERER (cells->data),
|
||||
(GtkCellLayoutDataFunc) escape_cell_data_func,
|
||||
escape_func,
|
||||
NULL);
|
||||
else
|
||||
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry),
|
||||
GTK_CELL_RENDERER (cells->data),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
g_list_free (cells);
|
||||
}
|
||||
96
xed/xed-history-entry.h
Normal file
96
xed/xed-history-entry.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* xed-history-entry.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2006 - Paolo Borelli
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2006. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_HISTORY_ENTRY_H__
|
||||
#define __XED_HISTORY_ENTRY_H__
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_HISTORY_ENTRY (xed_history_entry_get_type ())
|
||||
#define XED_HISTORY_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_HISTORY_ENTRY, XedHistoryEntry))
|
||||
#define XED_HISTORY_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_HISTORY_ENTRY, XedHistoryEntryClass))
|
||||
#define XED_IS_HISTORY_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_HISTORY_ENTRY))
|
||||
#define XED_IS_HISTORY_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_HISTORY_ENTRY))
|
||||
#define XED_HISTORY_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_HISTORY_ENTRY, XedHistoryEntryClass))
|
||||
|
||||
|
||||
typedef struct _XedHistoryEntry XedHistoryEntry;
|
||||
typedef struct _XedHistoryEntryClass XedHistoryEntryClass;
|
||||
typedef struct _XedHistoryEntryPrivate XedHistoryEntryPrivate;
|
||||
|
||||
struct _XedHistoryEntryClass
|
||||
{
|
||||
GtkComboBoxTextClass parent_class;
|
||||
};
|
||||
|
||||
struct _XedHistoryEntry
|
||||
{
|
||||
GtkComboBoxText parent_instance;
|
||||
|
||||
XedHistoryEntryPrivate *priv;
|
||||
};
|
||||
|
||||
GType xed_history_entry_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget *xed_history_entry_new (const gchar *history_id,
|
||||
gboolean enable_completion);
|
||||
|
||||
void xed_history_entry_prepend_text (XedHistoryEntry *entry,
|
||||
const gchar *text);
|
||||
|
||||
void xed_history_entry_append_text (XedHistoryEntry *entry,
|
||||
const gchar *text);
|
||||
|
||||
void xed_history_entry_clear (XedHistoryEntry *entry);
|
||||
|
||||
void xed_history_entry_set_history_length (XedHistoryEntry *entry,
|
||||
guint max_saved);
|
||||
|
||||
guint xed_history_entry_get_history_length (XedHistoryEntry *gentry);
|
||||
|
||||
gchar *xed_history_entry_get_history_id (XedHistoryEntry *entry);
|
||||
|
||||
void xed_history_entry_set_enable_completion
|
||||
(XedHistoryEntry *entry,
|
||||
gboolean enable);
|
||||
|
||||
gboolean xed_history_entry_get_enable_completion
|
||||
(XedHistoryEntry *entry);
|
||||
|
||||
GtkWidget *xed_history_entry_get_entry (XedHistoryEntry *entry);
|
||||
|
||||
typedef gchar * (* XedHistoryEntryEscapeFunc) (const gchar *str);
|
||||
void xed_history_entry_set_escape_func (XedHistoryEntry *entry,
|
||||
XedHistoryEntryEscapeFunc escape_func);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_HISTORY_ENTRY_H__ */
|
||||
1260
xed/xed-io-error-message-area.c
Normal file
1260
xed/xed-io-error-message-area.c
Normal file
File diff suppressed because it is too large
Load Diff
68
xed/xed-io-error-message-area.h
Normal file
68
xed/xed-io-error-message-area.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* xed-io-error-message-area.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_IO_ERROR_MESSAGE_AREA_H__
|
||||
#define __XED_IO_ERROR_MESSAGE_AREA_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GtkWidget *xed_io_loading_error_message_area_new (const gchar *uri,
|
||||
const XedEncoding *encoding,
|
||||
const GError *error);
|
||||
|
||||
GtkWidget *xed_unrecoverable_reverting_error_message_area_new (const gchar *uri,
|
||||
const GError *error);
|
||||
|
||||
GtkWidget *xed_conversion_error_while_saving_message_area_new (const gchar *uri,
|
||||
const XedEncoding *encoding,
|
||||
const GError *error);
|
||||
|
||||
const XedEncoding
|
||||
*xed_conversion_error_message_area_get_encoding (GtkWidget *message_area);
|
||||
|
||||
GtkWidget *xed_file_already_open_warning_message_area_new (const gchar *uri);
|
||||
|
||||
GtkWidget *xed_externally_modified_saving_error_message_area_new (const gchar *uri,
|
||||
const GError *error);
|
||||
|
||||
GtkWidget *xed_no_backup_saving_error_message_area_new (const gchar *uri,
|
||||
const GError *error);
|
||||
|
||||
GtkWidget *xed_unrecoverable_saving_error_message_area_new (const gchar *uri,
|
||||
const GError *error);
|
||||
|
||||
GtkWidget *xed_externally_modified_message_area_new (const gchar *uri,
|
||||
gboolean document_modified);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_IO_ERROR_MESSAGE_AREA_H__ */
|
||||
97
xed/xed-language-manager.c
Normal file
97
xed/xed-language-manager.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* xed-languages-manager.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2003-2006 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2003-2006. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gtk/gtk.h>
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
#include <gtksourceview/gtksource.h>
|
||||
#endif
|
||||
#include "xed-language-manager.h"
|
||||
#include "xed-prefs-manager.h"
|
||||
#include "xed-utils.h"
|
||||
#include "xed-debug.h"
|
||||
|
||||
static GtkSourceLanguageManager *language_manager = NULL;
|
||||
|
||||
GtkSourceLanguageManager *
|
||||
xed_get_language_manager (void)
|
||||
{
|
||||
if (language_manager == NULL)
|
||||
{
|
||||
language_manager = gtk_source_language_manager_new ();
|
||||
}
|
||||
|
||||
return language_manager;
|
||||
}
|
||||
|
||||
static gint
|
||||
language_compare (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
GtkSourceLanguage *lang_a = (GtkSourceLanguage *)a;
|
||||
GtkSourceLanguage *lang_b = (GtkSourceLanguage *)b;
|
||||
const gchar *name_a = gtk_source_language_get_name (lang_a);
|
||||
const gchar *name_b = gtk_source_language_get_name (lang_b);
|
||||
|
||||
return g_utf8_collate (name_a, name_b);
|
||||
}
|
||||
|
||||
GSList *
|
||||
xed_language_manager_list_languages_sorted (GtkSourceLanguageManager *lm,
|
||||
gboolean include_hidden)
|
||||
{
|
||||
GSList *languages = NULL;
|
||||
const gchar * const *ids;
|
||||
|
||||
ids = gtk_source_language_manager_get_language_ids (lm);
|
||||
if (ids == NULL)
|
||||
return NULL;
|
||||
|
||||
while (*ids != NULL)
|
||||
{
|
||||
GtkSourceLanguage *lang;
|
||||
|
||||
lang = gtk_source_language_manager_get_language (lm, *ids);
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
g_return_val_if_fail (GTK_SOURCE_IS_LANGUAGE (lang), NULL);
|
||||
#else
|
||||
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (lang), NULL);
|
||||
#endif
|
||||
++ids;
|
||||
|
||||
if (include_hidden || !gtk_source_language_get_hidden (lang))
|
||||
{
|
||||
languages = g_slist_prepend (languages, lang);
|
||||
}
|
||||
}
|
||||
|
||||
return g_slist_sort (languages, (GCompareFunc)language_compare);
|
||||
}
|
||||
|
||||
48
xed/xed-language-manager.h
Normal file
48
xed/xed-language-manager.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* xed-languages-manager.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2003-2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2003-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_LANGUAGES_MANAGER_H__
|
||||
#define __XED_LANGUAGES_MANAGER_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gtksourceview/gtksourcelanguagemanager.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GtkSourceLanguageManager *xed_get_language_manager (void);
|
||||
|
||||
GSList *xed_language_manager_list_languages_sorted
|
||||
(GtkSourceLanguageManager *lm,
|
||||
gboolean include_hidden);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_LANGUAGES_MANAGER_H__ */
|
||||
13
xed/xed-marshal.list
Normal file
13
xed/xed-marshal.list
Normal file
@@ -0,0 +1,13 @@
|
||||
BOOLEAN:NONE
|
||||
BOOLEAN:OBJECT
|
||||
VOID:BOOLEAN
|
||||
VOID:BOOLEAN,POINTER
|
||||
VOID:BOXED,BOXED
|
||||
VOID:OBJECT
|
||||
VOID:POINTER
|
||||
VOID:STRING,BOXED,FLAGS
|
||||
VOID:STRING,BOXED,INT,BOOLEAN
|
||||
VOID:UINT,POINTER
|
||||
VOID:UINT64,UINT64
|
||||
VOID:VOID
|
||||
VOID:INT,INT
|
||||
1158
xed/xed-message-bus.c
Normal file
1158
xed/xed-message-bus.c
Normal file
File diff suppressed because it is too large
Load Diff
129
xed/xed-message-bus.h
Normal file
129
xed/xed-message-bus.h
Normal file
@@ -0,0 +1,129 @@
|
||||
#ifndef __XED_MESSAGE_BUS_H__
|
||||
#define __XED_MESSAGE_BUS_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <xed/xed-message.h>
|
||||
#include <xed/xed-message-type.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_MESSAGE_BUS (xed_message_bus_get_type ())
|
||||
#define XED_MESSAGE_BUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_MESSAGE_BUS, XedMessageBus))
|
||||
#define XED_MESSAGE_BUS_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_MESSAGE_BUS, XedMessageBus const))
|
||||
#define XED_MESSAGE_BUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_MESSAGE_BUS, XedMessageBusClass))
|
||||
#define XED_IS_MESSAGE_BUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_MESSAGE_BUS))
|
||||
#define XED_IS_MESSAGE_BUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_MESSAGE_BUS))
|
||||
#define XED_MESSAGE_BUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_MESSAGE_BUS, XedMessageBusClass))
|
||||
|
||||
typedef struct _XedMessageBus XedMessageBus;
|
||||
typedef struct _XedMessageBusClass XedMessageBusClass;
|
||||
typedef struct _XedMessageBusPrivate XedMessageBusPrivate;
|
||||
|
||||
struct _XedMessageBus {
|
||||
GObject parent;
|
||||
|
||||
XedMessageBusPrivate *priv;
|
||||
};
|
||||
|
||||
struct _XedMessageBusClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*dispatch) (XedMessageBus *bus,
|
||||
XedMessage *message);
|
||||
void (*registered) (XedMessageBus *bus,
|
||||
XedMessageType *message_type);
|
||||
void (*unregistered) (XedMessageBus *bus,
|
||||
XedMessageType *message_type);
|
||||
};
|
||||
|
||||
typedef void (* XedMessageCallback) (XedMessageBus *bus,
|
||||
XedMessage *message,
|
||||
gpointer userdata);
|
||||
|
||||
typedef void (* XedMessageBusForeach) (XedMessageType *message_type,
|
||||
gpointer userdata);
|
||||
|
||||
GType xed_message_bus_get_type (void) G_GNUC_CONST;
|
||||
|
||||
XedMessageBus *xed_message_bus_get_default (void);
|
||||
XedMessageBus *xed_message_bus_new (void);
|
||||
|
||||
/* registering messages */
|
||||
XedMessageType *xed_message_bus_lookup (XedMessageBus *bus,
|
||||
const gchar *object_path,
|
||||
const gchar *method);
|
||||
XedMessageType *xed_message_bus_register (XedMessageBus *bus,
|
||||
const gchar *object_path,
|
||||
const gchar *method,
|
||||
guint num_optional,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
void xed_message_bus_unregister (XedMessageBus *bus,
|
||||
XedMessageType *message_type);
|
||||
|
||||
void xed_message_bus_unregister_all (XedMessageBus *bus,
|
||||
const gchar *object_path);
|
||||
|
||||
gboolean xed_message_bus_is_registered (XedMessageBus *bus,
|
||||
const gchar *object_path,
|
||||
const gchar *method);
|
||||
|
||||
void xed_message_bus_foreach (XedMessageBus *bus,
|
||||
XedMessageBusForeach func,
|
||||
gpointer userdata);
|
||||
|
||||
|
||||
/* connecting to message events */
|
||||
guint xed_message_bus_connect (XedMessageBus *bus,
|
||||
const gchar *object_path,
|
||||
const gchar *method,
|
||||
XedMessageCallback callback,
|
||||
gpointer userdata,
|
||||
GDestroyNotify destroy_data);
|
||||
|
||||
void xed_message_bus_disconnect (XedMessageBus *bus,
|
||||
guint id);
|
||||
|
||||
void xed_message_bus_disconnect_by_func (XedMessageBus *bus,
|
||||
const gchar *object_path,
|
||||
const gchar *method,
|
||||
XedMessageCallback callback,
|
||||
gpointer userdata);
|
||||
|
||||
/* blocking message event callbacks */
|
||||
void xed_message_bus_block (XedMessageBus *bus,
|
||||
guint id);
|
||||
void xed_message_bus_block_by_func (XedMessageBus *bus,
|
||||
const gchar *object_path,
|
||||
const gchar *method,
|
||||
XedMessageCallback callback,
|
||||
gpointer userdata);
|
||||
|
||||
void xed_message_bus_unblock (XedMessageBus *bus,
|
||||
guint id);
|
||||
void xed_message_bus_unblock_by_func (XedMessageBus *bus,
|
||||
const gchar *object_path,
|
||||
const gchar *method,
|
||||
XedMessageCallback callback,
|
||||
gpointer userdata);
|
||||
|
||||
/* sending messages */
|
||||
void xed_message_bus_send_message (XedMessageBus *bus,
|
||||
XedMessage *message);
|
||||
void xed_message_bus_send_message_sync (XedMessageBus *bus,
|
||||
XedMessage *message);
|
||||
|
||||
void xed_message_bus_send (XedMessageBus *bus,
|
||||
const gchar *object_path,
|
||||
const gchar *method,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
XedMessage *xed_message_bus_send_sync (XedMessageBus *bus,
|
||||
const gchar *object_path,
|
||||
const gchar *method,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_MESSAGE_BUS_H__ */
|
||||
|
||||
// ex:ts=8:noet:
|
||||
527
xed/xed-message-type.c
Normal file
527
xed/xed-message-type.c
Normal file
@@ -0,0 +1,527 @@
|
||||
#include "xed-message-type.h"
|
||||
|
||||
/**
|
||||
* SECTION:xed-message-type
|
||||
* @short_description: message type description
|
||||
* @include: xed/xed-message-type.h
|
||||
*
|
||||
* A message type is a prototype description for a #XedMessage used to
|
||||
* transmit messages on a #XedMessageBus. The message type describes
|
||||
* the Object Path, Method and Arguments of the message.
|
||||
*
|
||||
* A message type can contain any number of required and optional arguments.
|
||||
* To instantiate a #XedMessage from a #XedMessageType, use
|
||||
* xed_message_type_instantiate().
|
||||
*
|
||||
* Registering a new message type on a #XedMessageBus with
|
||||
* xed_message_bus_register() internally creates a new #XedMessageType. When
|
||||
* then using xed_message_bus_send(), an actual instantiation of the
|
||||
* registered type is internally created and send over the bus.
|
||||
*
|
||||
* <example>
|
||||
* <programlisting>
|
||||
* // Defining a new message type
|
||||
* XedMessageType *message_type = xed_message_type_new ("/plugins/example",
|
||||
* "method",
|
||||
* 0,
|
||||
* "arg1", G_TYPE_STRING,
|
||||
* NULL);
|
||||
*
|
||||
* // Instantiating an actual message from the type
|
||||
* XedMessage *message = xed_message_type_instantiate (message_type,
|
||||
* "arg1", "Hello World",
|
||||
* NULL);
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* Since: 2.25.3
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GType type;
|
||||
gboolean required;
|
||||
} ArgumentInfo;
|
||||
|
||||
struct _XedMessageType
|
||||
{
|
||||
/* FIXME this is an issue for introspection */
|
||||
gint ref_count;
|
||||
|
||||
gchar *object_path;
|
||||
gchar *method;
|
||||
|
||||
guint num_arguments;
|
||||
guint num_required;
|
||||
|
||||
GHashTable *arguments; // mapping of key -> ArgumentInfo
|
||||
};
|
||||
|
||||
/**
|
||||
* xed_message_type_ref:
|
||||
* @message_type: the #XedMessageType
|
||||
*
|
||||
* Increases the reference count on @message_type.
|
||||
*
|
||||
* Return value: @message_type
|
||||
*
|
||||
*/
|
||||
XedMessageType *
|
||||
xed_message_type_ref (XedMessageType *message_type)
|
||||
{
|
||||
g_return_val_if_fail (message_type != NULL, NULL);
|
||||
g_atomic_int_inc (&message_type->ref_count);
|
||||
|
||||
return message_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_unref:
|
||||
* @message_type: the #XedMessageType
|
||||
*
|
||||
* Decreases the reference count on @message_type. When the reference count
|
||||
* drops to 0, @message_type is destroyed.
|
||||
*
|
||||
*/
|
||||
void
|
||||
xed_message_type_unref (XedMessageType *message_type)
|
||||
{
|
||||
g_return_if_fail (message_type != NULL);
|
||||
|
||||
if (!g_atomic_int_dec_and_test (&message_type->ref_count))
|
||||
return;
|
||||
|
||||
g_free (message_type->object_path);
|
||||
g_free (message_type->method);
|
||||
|
||||
g_hash_table_destroy (message_type->arguments);
|
||||
g_free (message_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_get_type:
|
||||
*
|
||||
* Retrieves the GType object which is associated with the
|
||||
* #XedMessageType class.
|
||||
*
|
||||
* Return value: the GType associated with #XedMessageType.
|
||||
**/
|
||||
GType
|
||||
xed_message_type_get_type (void)
|
||||
{
|
||||
static GType our_type = 0;
|
||||
|
||||
if (!our_type)
|
||||
our_type = g_boxed_type_register_static (
|
||||
"XedMessageType",
|
||||
(GBoxedCopyFunc) xed_message_type_ref,
|
||||
(GBoxedFreeFunc) xed_message_type_unref);
|
||||
|
||||
return our_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_identifier:
|
||||
* @object_path: (allow-none): the object path
|
||||
* @method: (allow-none): the method
|
||||
*
|
||||
* Get the string identifier for @method at @object_path.
|
||||
*
|
||||
* Return value: the identifier for @method at @object_path
|
||||
*
|
||||
*/
|
||||
gchar *
|
||||
xed_message_type_identifier (const gchar *object_path,
|
||||
const gchar *method)
|
||||
{
|
||||
return g_strconcat (object_path, ".", method, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_is_valid_object_path:
|
||||
* @object_path: (allow-none): the object path
|
||||
*
|
||||
* Returns whether @object_path is a valid object path
|
||||
*
|
||||
* Return value: %TRUE if @object_path is a valid object path
|
||||
*
|
||||
*/
|
||||
gboolean
|
||||
xed_message_type_is_valid_object_path (const gchar *object_path)
|
||||
{
|
||||
if (!object_path)
|
||||
return FALSE;
|
||||
|
||||
/* needs to start with / */
|
||||
if (*object_path != '/')
|
||||
return FALSE;
|
||||
|
||||
while (*object_path)
|
||||
{
|
||||
if (*object_path == '/')
|
||||
{
|
||||
++object_path;
|
||||
|
||||
if (!*object_path || !(g_ascii_isalpha (*object_path) || *object_path == '_'))
|
||||
return FALSE;
|
||||
}
|
||||
else if (!(g_ascii_isalnum (*object_path) || *object_path == '_'))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
++object_path;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_is_supported:
|
||||
* @type: the #GType
|
||||
*
|
||||
* Returns if @type is #GType supported by the message system.
|
||||
*
|
||||
* Return value: %TRUE if @type is a supported #GType
|
||||
*
|
||||
*/
|
||||
gboolean
|
||||
xed_message_type_is_supported (GType type)
|
||||
{
|
||||
gint i = 0;
|
||||
|
||||
static const GType type_list[] =
|
||||
{
|
||||
G_TYPE_BOOLEAN,
|
||||
G_TYPE_CHAR,
|
||||
G_TYPE_UCHAR,
|
||||
G_TYPE_INT,
|
||||
G_TYPE_UINT,
|
||||
G_TYPE_LONG,
|
||||
G_TYPE_ULONG,
|
||||
G_TYPE_INT64,
|
||||
G_TYPE_UINT64,
|
||||
G_TYPE_ENUM,
|
||||
G_TYPE_FLAGS,
|
||||
G_TYPE_FLOAT,
|
||||
G_TYPE_DOUBLE,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_POINTER,
|
||||
G_TYPE_BOXED,
|
||||
G_TYPE_OBJECT,
|
||||
G_TYPE_INVALID
|
||||
};
|
||||
|
||||
if (!G_TYPE_IS_VALUE_TYPE (type))
|
||||
return FALSE;
|
||||
|
||||
while (type_list[i] != G_TYPE_INVALID)
|
||||
{
|
||||
if (g_type_is_a (type, type_list[i]))
|
||||
return TRUE;
|
||||
i++;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_new_valist:
|
||||
* @object_path: (allow-none): the object path
|
||||
* @method: (allow-none): the method
|
||||
* @num_optional: number of optional arguments
|
||||
* @var_args: key/gtype pair variable argument list
|
||||
*
|
||||
* Create a new #XedMessageType for @method at @object_path. Argument names
|
||||
* and values are supplied by the NULL terminated variable argument list.
|
||||
* The last @num_optional provided arguments are considered optional.
|
||||
*
|
||||
* Return value: the newly constructed #XedMessageType
|
||||
*
|
||||
*/
|
||||
XedMessageType *
|
||||
xed_message_type_new_valist (const gchar *object_path,
|
||||
const gchar *method,
|
||||
guint num_optional,
|
||||
va_list var_args)
|
||||
{
|
||||
XedMessageType *message_type;
|
||||
|
||||
g_return_val_if_fail (object_path != NULL, NULL);
|
||||
g_return_val_if_fail (method != NULL, NULL);
|
||||
g_return_val_if_fail (xed_message_type_is_valid_object_path (object_path), NULL);
|
||||
|
||||
message_type = g_new0(XedMessageType, 1);
|
||||
|
||||
message_type->ref_count = 1;
|
||||
message_type->object_path = g_strdup(object_path);
|
||||
message_type->method = g_strdup(method);
|
||||
message_type->num_arguments = 0;
|
||||
message_type->arguments = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
(GDestroyNotify)g_free,
|
||||
(GDestroyNotify)g_free);
|
||||
|
||||
xed_message_type_set_valist (message_type, num_optional, var_args);
|
||||
return message_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_new:
|
||||
* @object_path: (allow-none): the object path
|
||||
* @method: (allow-none): the method
|
||||
* @num_optional: number of optional arguments
|
||||
* @...: key/gtype pair variable argument list
|
||||
*
|
||||
* Create a new #XedMessageType for @method at @object_path. Argument names
|
||||
* and values are supplied by the NULL terminated variable argument list.
|
||||
* The last @num_optional provided arguments are considered optional.
|
||||
*
|
||||
* Return value: the newly constructed #XedMessageType
|
||||
*
|
||||
*/
|
||||
XedMessageType *
|
||||
xed_message_type_new (const gchar *object_path,
|
||||
const gchar *method,
|
||||
guint num_optional,
|
||||
...)
|
||||
{
|
||||
XedMessageType *message_type;
|
||||
va_list var_args;
|
||||
|
||||
va_start(var_args, num_optional);
|
||||
message_type = xed_message_type_new_valist (object_path, method, num_optional, var_args);
|
||||
va_end(var_args);
|
||||
|
||||
return message_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_set:
|
||||
* @message_type: the #XedMessageType
|
||||
* @num_optional: number of optional arguments
|
||||
* @...: key/gtype pair variable argument list
|
||||
*
|
||||
* Sets argument names/types supplied by the NULL terminated variable
|
||||
* argument list. The last @num_optional provided arguments are considered
|
||||
* optional.
|
||||
*
|
||||
*/
|
||||
void
|
||||
xed_message_type_set (XedMessageType *message_type,
|
||||
guint num_optional,
|
||||
...)
|
||||
{
|
||||
va_list va_args;
|
||||
|
||||
va_start (va_args, num_optional);
|
||||
xed_message_type_set_valist (message_type, num_optional, va_args);
|
||||
va_end (va_args);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_set_valist:
|
||||
* @message_type: the #XedMessageType
|
||||
* @num_optional: number of optional arguments
|
||||
* @var_args: key/gtype pair variable argument list
|
||||
*
|
||||
* Sets argument names/types supplied by the NULL terminated variable
|
||||
* argument list @var_args. The last @num_optional provided arguments are
|
||||
* considered optional.
|
||||
*
|
||||
*/
|
||||
void
|
||||
xed_message_type_set_valist (XedMessageType *message_type,
|
||||
guint num_optional,
|
||||
va_list var_args)
|
||||
{
|
||||
const gchar *key;
|
||||
ArgumentInfo **optional = g_new0(ArgumentInfo *, num_optional);
|
||||
guint i;
|
||||
guint added = 0;
|
||||
|
||||
// parse key -> gtype pair arguments
|
||||
while ((key = va_arg (var_args, const gchar *)) != NULL)
|
||||
{
|
||||
// get corresponding GType
|
||||
GType gtype = va_arg (var_args, GType);
|
||||
ArgumentInfo *info;
|
||||
|
||||
if (!xed_message_type_is_supported (gtype))
|
||||
{
|
||||
g_error ("Message type '%s' is not supported", g_type_name (gtype));
|
||||
|
||||
xed_message_type_unref (message_type);
|
||||
g_free (optional);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
info = g_new(ArgumentInfo, 1);
|
||||
info->type = gtype;
|
||||
info->required = TRUE;
|
||||
|
||||
g_hash_table_insert (message_type->arguments, g_strdup (key), info);
|
||||
|
||||
++message_type->num_arguments;
|
||||
++added;
|
||||
|
||||
if (num_optional > 0)
|
||||
{
|
||||
for (i = num_optional - 1; i > 0; --i)
|
||||
optional[i] = optional[i - 1];
|
||||
|
||||
*optional = info;
|
||||
}
|
||||
}
|
||||
|
||||
message_type->num_required += added;
|
||||
|
||||
// set required for last num_optional arguments
|
||||
for (i = 0; i < num_optional; ++i)
|
||||
{
|
||||
if (optional[i])
|
||||
{
|
||||
optional[i]->required = FALSE;
|
||||
--message_type->num_required;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (optional);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_instantiate_valist:
|
||||
* @message_type: the #XedMessageType
|
||||
* @va_args: NULL terminated variable list of key/value pairs
|
||||
*
|
||||
* Instantiate a new message from the message type with specific values
|
||||
* for the message arguments.
|
||||
*
|
||||
* Return value: the newly created message
|
||||
*
|
||||
*/
|
||||
XedMessage *
|
||||
xed_message_type_instantiate_valist (XedMessageType *message_type,
|
||||
va_list va_args)
|
||||
{
|
||||
XedMessage *message;
|
||||
|
||||
g_return_val_if_fail (message_type != NULL, NULL);
|
||||
|
||||
message = XED_MESSAGE (g_object_new (XED_TYPE_MESSAGE, "type", message_type, NULL));
|
||||
xed_message_set_valist (message, va_args);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_instantiate:
|
||||
* @message_type: the #XedMessageType
|
||||
* @...: NULL terminated variable list of key/value pairs
|
||||
*
|
||||
* Instantiate a new message from the message type with specific values
|
||||
* for the message arguments.
|
||||
*
|
||||
* Return value: the newly created message
|
||||
*
|
||||
*/
|
||||
XedMessage *
|
||||
xed_message_type_instantiate (XedMessageType *message_type,
|
||||
...)
|
||||
{
|
||||
XedMessage *message;
|
||||
va_list va_args;
|
||||
|
||||
va_start (va_args, message_type);
|
||||
message = xed_message_type_instantiate_valist (message_type, va_args);
|
||||
va_end (va_args);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_get_object_path:
|
||||
* @message_type: the #XedMessageType
|
||||
*
|
||||
* Get the message type object path.
|
||||
*
|
||||
* Return value: the message type object path
|
||||
*
|
||||
*/
|
||||
const gchar *
|
||||
xed_message_type_get_object_path (XedMessageType *message_type)
|
||||
{
|
||||
return message_type->object_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_get_method:
|
||||
* @message_type: the #XedMessageType
|
||||
*
|
||||
* Get the message type method.
|
||||
*
|
||||
* Return value: the message type method
|
||||
*
|
||||
*/
|
||||
const gchar *
|
||||
xed_message_type_get_method (XedMessageType *message_type)
|
||||
{
|
||||
return message_type->method;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_lookup:
|
||||
* @message_type: the #XedMessageType
|
||||
* @key: the argument key
|
||||
*
|
||||
* Get the argument key #GType.
|
||||
*
|
||||
* Return value: the #GType of @key
|
||||
*
|
||||
*/
|
||||
GType
|
||||
xed_message_type_lookup (XedMessageType *message_type,
|
||||
const gchar *key)
|
||||
{
|
||||
ArgumentInfo *info = g_hash_table_lookup (message_type->arguments, key);
|
||||
|
||||
if (!info)
|
||||
return G_TYPE_INVALID;
|
||||
|
||||
return info->type;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
XedMessageTypeForeach func;
|
||||
gpointer user_data;
|
||||
} ForeachInfo;
|
||||
|
||||
static void
|
||||
foreach_gtype (const gchar *key,
|
||||
ArgumentInfo *info,
|
||||
ForeachInfo *finfo)
|
||||
{
|
||||
finfo->func (key, info->type, info->required, finfo->user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_type_foreach:
|
||||
* @message_type: the #XedMessageType
|
||||
* @func: the callback function
|
||||
* @user_data: user data supplied to the callback function
|
||||
*
|
||||
* Calls @func for each argument in the message type.
|
||||
*
|
||||
*/
|
||||
void
|
||||
xed_message_type_foreach (XedMessageType *message_type,
|
||||
XedMessageTypeForeach func,
|
||||
gpointer user_data)
|
||||
{
|
||||
ForeachInfo info = {func, user_data};
|
||||
g_hash_table_foreach (message_type->arguments, (GHFunc)foreach_gtype, &info);
|
||||
}
|
||||
|
||||
// ex:ts=8:noet:
|
||||
67
xed/xed-message-type.h
Normal file
67
xed/xed-message-type.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef __XED_MESSAGE_TYPE_H__
|
||||
#define __XED_MESSAGE_TYPE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "xed-message.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_MESSAGE_TYPE (xed_message_type_get_type ())
|
||||
#define XED_MESSAGE_TYPE(x) ((XedMessageType *)(x))
|
||||
|
||||
typedef void (*XedMessageTypeForeach) (const gchar *key,
|
||||
GType type,
|
||||
gboolean required,
|
||||
gpointer user_data);
|
||||
|
||||
typedef struct _XedMessageType XedMessageType;
|
||||
|
||||
GType xed_message_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
gboolean xed_message_type_is_supported (GType type);
|
||||
gchar *xed_message_type_identifier (const gchar *object_path,
|
||||
const gchar *method);
|
||||
gboolean xed_message_type_is_valid_object_path (const gchar *object_path);
|
||||
|
||||
XedMessageType *xed_message_type_new (const gchar *object_path,
|
||||
const gchar *method,
|
||||
guint num_optional,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
XedMessageType *xed_message_type_new_valist (const gchar *object_path,
|
||||
const gchar *method,
|
||||
guint num_optional,
|
||||
va_list va_args);
|
||||
|
||||
void xed_message_type_set (XedMessageType *message_type,
|
||||
guint num_optional,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
void xed_message_type_set_valist (XedMessageType *message_type,
|
||||
guint num_optional,
|
||||
va_list va_args);
|
||||
|
||||
XedMessageType *xed_message_type_ref (XedMessageType *message_type);
|
||||
void xed_message_type_unref (XedMessageType *message_type);
|
||||
|
||||
|
||||
XedMessage *xed_message_type_instantiate_valist (XedMessageType *message_type,
|
||||
va_list va_args);
|
||||
XedMessage *xed_message_type_instantiate (XedMessageType *message_type,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
const gchar *xed_message_type_get_object_path (XedMessageType *message_type);
|
||||
const gchar *xed_message_type_get_method (XedMessageType *message_type);
|
||||
|
||||
GType xed_message_type_lookup (XedMessageType *message_type,
|
||||
const gchar *key);
|
||||
|
||||
void xed_message_type_foreach (XedMessageType *message_type,
|
||||
XedMessageTypeForeach func,
|
||||
gpointer user_data);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_MESSAGE_TYPE_H__ */
|
||||
|
||||
// ex:ts=8:noet:
|
||||
594
xed/xed-message.c
Normal file
594
xed/xed-message.c
Normal file
@@ -0,0 +1,594 @@
|
||||
#include "xed-message.h"
|
||||
#include "xed-message-type.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <gobject/gvaluecollector.h>
|
||||
|
||||
/**
|
||||
* SECTION:xed-message
|
||||
* @short_description: message bus message object
|
||||
* @include: xed/xed-message.h
|
||||
*
|
||||
* Communication on a #XedMessageBus is done through messages. Messages are
|
||||
* sent over the bus and received by connecting callbacks on the message bus.
|
||||
* A #XedMessage is an instantiation of a #XedMessageType, containing
|
||||
* values for the arguments as specified in the message type.
|
||||
*
|
||||
* A message can be seen as a method call, or signal emission depending on
|
||||
* who is the sender and who is the receiver. There is no explicit distinction
|
||||
* between methods and signals.
|
||||
*
|
||||
* Since: 2.25.3
|
||||
*
|
||||
*/
|
||||
#define XED_MESSAGE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), XED_TYPE_MESSAGE, XedMessagePrivate))
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
PROP_OBJECT_PATH,
|
||||
PROP_METHOD,
|
||||
PROP_TYPE
|
||||
};
|
||||
|
||||
struct _XedMessagePrivate
|
||||
{
|
||||
XedMessageType *type;
|
||||
gboolean valid;
|
||||
|
||||
GHashTable *values;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (XedMessage, xed_message, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
xed_message_finalize (GObject *object)
|
||||
{
|
||||
XedMessage *message = XED_MESSAGE (object);
|
||||
|
||||
xed_message_type_unref (message->priv->type);
|
||||
g_hash_table_destroy (message->priv->values);
|
||||
|
||||
G_OBJECT_CLASS (xed_message_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_message_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedMessage *msg = XED_MESSAGE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_OBJECT_PATH:
|
||||
g_value_set_string (value, xed_message_type_get_object_path (msg->priv->type));
|
||||
break;
|
||||
case PROP_METHOD:
|
||||
g_value_set_string (value, xed_message_type_get_method (msg->priv->type));
|
||||
break;
|
||||
case PROP_TYPE:
|
||||
g_value_set_boxed (value, msg->priv->type);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_message_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedMessage *msg = XED_MESSAGE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_TYPE:
|
||||
msg->priv->type = XED_MESSAGE_TYPE (g_value_dup_boxed (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GValue *
|
||||
add_value (XedMessage *message,
|
||||
const gchar *key)
|
||||
{
|
||||
GValue *value;
|
||||
GType type = xed_message_type_lookup (message->priv->type, key);
|
||||
|
||||
if (type == G_TYPE_INVALID)
|
||||
return NULL;
|
||||
|
||||
value = g_new0 (GValue, 1);
|
||||
g_value_init (value, type);
|
||||
g_value_reset (value);
|
||||
|
||||
g_hash_table_insert (message->priv->values, g_strdup (key), value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void
|
||||
xed_message_class_init (XedMessageClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->finalize = xed_message_finalize;
|
||||
object_class->get_property = xed_message_get_property;
|
||||
object_class->set_property = xed_message_set_property;
|
||||
|
||||
/**
|
||||
* XedMessage:object_path:
|
||||
*
|
||||
* The messages object path (e.g. /xed/object/path).
|
||||
*
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_OBJECT_PATH,
|
||||
g_param_spec_string ("object-path",
|
||||
"OBJECT_PATH",
|
||||
"The message object path",
|
||||
NULL,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* XedMessage:method:
|
||||
*
|
||||
* The messages method.
|
||||
*
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_METHOD,
|
||||
g_param_spec_string ("method",
|
||||
"METHOD",
|
||||
"The message method",
|
||||
NULL,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* XedMEssage:type:
|
||||
*
|
||||
* The message type.
|
||||
*
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_TYPE,
|
||||
g_param_spec_boxed ("type",
|
||||
"TYPE",
|
||||
"The message type",
|
||||
XED_TYPE_MESSAGE_TYPE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_type_class_add_private (object_class, sizeof(XedMessagePrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_value (GValue *value)
|
||||
{
|
||||
g_value_unset (value);
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_message_init (XedMessage *self)
|
||||
{
|
||||
self->priv = XED_MESSAGE_GET_PRIVATE (self);
|
||||
|
||||
self->priv->values = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
(GDestroyNotify)g_free,
|
||||
(GDestroyNotify)destroy_value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_value_real (GValue *to,
|
||||
const GValue *from)
|
||||
{
|
||||
GType from_type;
|
||||
GType to_type;
|
||||
|
||||
from_type = G_VALUE_TYPE (from);
|
||||
to_type = G_VALUE_TYPE (to);
|
||||
|
||||
if (!g_type_is_a (from_type, to_type))
|
||||
{
|
||||
if (!g_value_transform (from, to))
|
||||
{
|
||||
g_warning ("%s: Unable to make conversion from %s to %s",
|
||||
G_STRLOC,
|
||||
g_type_name (from_type),
|
||||
g_type_name (to_type));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_value_copy (from, to);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
inline static GValue *
|
||||
value_lookup (XedMessage *message,
|
||||
const gchar *key,
|
||||
gboolean create)
|
||||
{
|
||||
GValue *ret = (GValue *)g_hash_table_lookup (message->priv->values, key);
|
||||
|
||||
if (!ret && create)
|
||||
ret = add_value (message, key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_get_method:
|
||||
* @message: the #XedMessage
|
||||
*
|
||||
* Get the message method.
|
||||
*
|
||||
* Return value: the message method
|
||||
*
|
||||
*/
|
||||
const gchar *
|
||||
xed_message_get_method (XedMessage *message)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_MESSAGE (message), NULL);
|
||||
|
||||
return xed_message_type_get_method (message->priv->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_get_object_path:
|
||||
* @message: the #XedMessage
|
||||
*
|
||||
* Get the message object path.
|
||||
*
|
||||
* Return value: the message object path
|
||||
*
|
||||
*/
|
||||
const gchar *
|
||||
xed_message_get_object_path (XedMessage *message)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_MESSAGE (message), NULL);
|
||||
|
||||
return xed_message_type_get_object_path (message->priv->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_set:
|
||||
* @message: the #XedMessage
|
||||
* @...: a %NULL terminated variable list of key/value pairs
|
||||
*
|
||||
* Set values of message arguments. The supplied @var_args should contain
|
||||
* pairs of keys and argument values.
|
||||
*
|
||||
*/
|
||||
void
|
||||
xed_message_set (XedMessage *message,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
g_return_if_fail (XED_IS_MESSAGE (message));
|
||||
|
||||
va_start (ap, message);
|
||||
xed_message_set_valist (message, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_set_valist:
|
||||
* @message: the #XedMessage
|
||||
* @var_args: a %NULL terminated variable list of key/value pairs
|
||||
*
|
||||
* Set values of message arguments. The supplied @var_args should contain
|
||||
* pairs of keys and argument values.
|
||||
*
|
||||
*/
|
||||
void
|
||||
xed_message_set_valist (XedMessage *message,
|
||||
va_list var_args)
|
||||
{
|
||||
const gchar *key;
|
||||
|
||||
g_return_if_fail (XED_IS_MESSAGE (message));
|
||||
|
||||
while ((key = va_arg (var_args, const gchar *)) != NULL)
|
||||
{
|
||||
/* lookup the key */
|
||||
GValue *container = value_lookup (message, key, TRUE);
|
||||
GValue value = {0,};
|
||||
gchar *error = NULL;
|
||||
|
||||
if (!container)
|
||||
{
|
||||
g_warning ("%s: Cannot set value for %s, does not exist",
|
||||
G_STRLOC,
|
||||
key);
|
||||
|
||||
/* skip value */
|
||||
va_arg (var_args, gpointer);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_value_init (&value, G_VALUE_TYPE (container));
|
||||
G_VALUE_COLLECT (&value, var_args, 0, &error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_warning ("%s: %s", G_STRLOC, error);
|
||||
continue;
|
||||
}
|
||||
|
||||
set_value_real (container, &value);
|
||||
g_value_unset (&value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_set_value:
|
||||
* @message: the #XedMessage
|
||||
* @key: the argument key
|
||||
* @value: (out): the argument value
|
||||
*
|
||||
* Set value of message argument @key to @value.
|
||||
*
|
||||
*/
|
||||
void
|
||||
xed_message_set_value (XedMessage *message,
|
||||
const gchar *key,
|
||||
GValue *value)
|
||||
{
|
||||
GValue *container;
|
||||
g_return_if_fail (XED_IS_MESSAGE (message));
|
||||
|
||||
container = value_lookup (message, key, TRUE);
|
||||
|
||||
if (!container)
|
||||
{
|
||||
g_warning ("%s: Cannot set value for %s, does not exist",
|
||||
G_STRLOC,
|
||||
key);
|
||||
return;
|
||||
}
|
||||
|
||||
set_value_real (container, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_set_valuesv:
|
||||
* @message: the #XedMessage
|
||||
* @keys: (array-length=n_values): keys to set values for
|
||||
* @values: (array-length=n_values): values to set
|
||||
* @n_values: number of arguments to set values for
|
||||
*
|
||||
* Set message argument values.
|
||||
*
|
||||
*/
|
||||
void
|
||||
xed_message_set_valuesv (XedMessage *message,
|
||||
const gchar **keys,
|
||||
GValue *values,
|
||||
gint n_values)
|
||||
{
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (XED_IS_MESSAGE (message));
|
||||
|
||||
for (i = 0; i < n_values; i++)
|
||||
{
|
||||
xed_message_set_value (message, keys[i], &values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME this is an issue for introspection */
|
||||
/**
|
||||
* xed_message_get:
|
||||
* @message: the #XedMessage
|
||||
* @...: a %NULL variable argument list of key/value container pairs
|
||||
*
|
||||
* Get values of message arguments. The supplied @var_args should contain
|
||||
* pairs of keys and pointers to variables which are set to the argument
|
||||
* value for the specified key.
|
||||
*
|
||||
*/
|
||||
void
|
||||
xed_message_get (XedMessage *message,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
g_return_if_fail (XED_IS_MESSAGE (message));
|
||||
|
||||
va_start (ap, message);
|
||||
xed_message_get_valist (message, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_get_valist:
|
||||
* @message: the #XedMessage
|
||||
* @var_args: a %NULL variable argument list of key/value container pairs
|
||||
*
|
||||
* Get values of message arguments. The supplied @var_args should contain
|
||||
* pairs of keys and pointers to variables which are set to the argument
|
||||
* value for the specified key.
|
||||
*
|
||||
*/
|
||||
void
|
||||
xed_message_get_valist (XedMessage *message,
|
||||
va_list var_args)
|
||||
{
|
||||
const gchar *key;
|
||||
|
||||
g_return_if_fail (XED_IS_MESSAGE (message));
|
||||
|
||||
while ((key = va_arg (var_args, const gchar *)) != NULL)
|
||||
{
|
||||
GValue *container;
|
||||
GValue copy = {0,};
|
||||
gchar *error = NULL;
|
||||
|
||||
container = value_lookup (message, key, FALSE);
|
||||
|
||||
if (!container)
|
||||
{
|
||||
/* skip value */
|
||||
va_arg (var_args, gpointer);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* copy the value here, to be sure it isn't tainted */
|
||||
g_value_init (©, G_VALUE_TYPE (container));
|
||||
g_value_copy (container, ©);
|
||||
|
||||
G_VALUE_LCOPY (©, var_args, 0, &error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_warning ("%s: %s", G_STRLOC, error);
|
||||
g_free (error);
|
||||
|
||||
/* purposely leak the value here, because it might
|
||||
be in a bad state */
|
||||
continue;
|
||||
}
|
||||
|
||||
g_value_unset (©);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_get_value:
|
||||
* @message: the #XedMessage
|
||||
* @key: the argument key
|
||||
* @value: (out): value return container
|
||||
*
|
||||
* Get the value of a specific message argument. @value will be initialized
|
||||
* with the correct type.
|
||||
*
|
||||
*/
|
||||
void
|
||||
xed_message_get_value (XedMessage *message,
|
||||
const gchar *key,
|
||||
GValue *value)
|
||||
{
|
||||
GValue *container;
|
||||
|
||||
g_return_if_fail (XED_IS_MESSAGE (message));
|
||||
|
||||
container = value_lookup (message, key, FALSE);
|
||||
|
||||
if (!container)
|
||||
{
|
||||
g_warning ("%s: Invalid key `%s'",
|
||||
G_STRLOC,
|
||||
key);
|
||||
return;
|
||||
}
|
||||
|
||||
g_value_init (value, G_VALUE_TYPE (container));
|
||||
set_value_real (value, container);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_get_key_type:
|
||||
* @message: the #XedMessage
|
||||
* @key: the argument key
|
||||
*
|
||||
* Get the type of a message argument.
|
||||
*
|
||||
* Return value: the type of @key
|
||||
*
|
||||
*/
|
||||
GType
|
||||
xed_message_get_key_type (XedMessage *message,
|
||||
const gchar *key)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_MESSAGE (message), G_TYPE_INVALID);
|
||||
g_return_val_if_fail (message->priv->type != NULL, G_TYPE_INVALID);
|
||||
|
||||
return xed_message_type_lookup (message->priv->type, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_has_key:
|
||||
* @message: the #XedMessage
|
||||
* @key: the argument key
|
||||
*
|
||||
* Check whether the message has a specific key.
|
||||
*
|
||||
* Return value: %TRUE if @message has argument @key
|
||||
*
|
||||
*/
|
||||
gboolean
|
||||
xed_message_has_key (XedMessage *message,
|
||||
const gchar *key)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_MESSAGE (message), FALSE);
|
||||
|
||||
return value_lookup (message, key, FALSE) != NULL;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
XedMessage *message;
|
||||
gboolean valid;
|
||||
} ValidateInfo;
|
||||
|
||||
static void
|
||||
validate_key (const gchar *key,
|
||||
GType type,
|
||||
gboolean required,
|
||||
ValidateInfo *info)
|
||||
{
|
||||
GValue *value;
|
||||
|
||||
if (!info->valid || !required)
|
||||
return;
|
||||
|
||||
value = value_lookup (info->message, key, FALSE);
|
||||
|
||||
if (!value)
|
||||
info->valid = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_message_validate:
|
||||
* @message: the #XedMessage
|
||||
*
|
||||
* Validates the message arguments according to the message type.
|
||||
*
|
||||
* Return value: %TRUE if the message is valid
|
||||
*
|
||||
*/
|
||||
gboolean
|
||||
xed_message_validate (XedMessage *message)
|
||||
{
|
||||
ValidateInfo info = {message, TRUE};
|
||||
|
||||
g_return_val_if_fail (XED_IS_MESSAGE (message), FALSE);
|
||||
g_return_val_if_fail (message->priv->type != NULL, FALSE);
|
||||
|
||||
if (!message->priv->valid)
|
||||
{
|
||||
xed_message_type_foreach (message->priv->type,
|
||||
(XedMessageTypeForeach)validate_key,
|
||||
&info);
|
||||
|
||||
message->priv->valid = info.valid;
|
||||
}
|
||||
|
||||
return message->priv->valid;
|
||||
}
|
||||
|
||||
// ex:ts=8:noet:
|
||||
71
xed/xed-message.h
Normal file
71
xed/xed-message.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef __XED_MESSAGE_H__
|
||||
#define __XED_MESSAGE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_MESSAGE (xed_message_get_type ())
|
||||
#define XED_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_MESSAGE, XedMessage))
|
||||
#define XED_MESSAGE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_MESSAGE, XedMessage const))
|
||||
#define XED_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_MESSAGE, XedMessageClass))
|
||||
#define XED_IS_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_MESSAGE))
|
||||
#define XED_IS_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_MESSAGE))
|
||||
#define XED_MESSAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_MESSAGE, XedMessageClass))
|
||||
|
||||
typedef struct _XedMessage XedMessage;
|
||||
typedef struct _XedMessageClass XedMessageClass;
|
||||
typedef struct _XedMessagePrivate XedMessagePrivate;
|
||||
|
||||
struct _XedMessage {
|
||||
GObject parent;
|
||||
|
||||
XedMessagePrivate *priv;
|
||||
};
|
||||
|
||||
struct _XedMessageClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
GType xed_message_get_type (void) G_GNUC_CONST;
|
||||
|
||||
struct _XedMessageType xed_message_get_message_type (XedMessage *message);
|
||||
|
||||
void xed_message_get (XedMessage *message,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
void xed_message_get_valist (XedMessage *message,
|
||||
va_list var_args);
|
||||
void xed_message_get_value (XedMessage *message,
|
||||
const gchar *key,
|
||||
GValue *value);
|
||||
|
||||
void xed_message_set (XedMessage *message,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
void xed_message_set_valist (XedMessage *message,
|
||||
va_list var_args);
|
||||
void xed_message_set_value (XedMessage *message,
|
||||
const gchar *key,
|
||||
GValue *value);
|
||||
void xed_message_set_valuesv (XedMessage *message,
|
||||
const gchar **keys,
|
||||
GValue *values,
|
||||
gint n_values);
|
||||
|
||||
const gchar *xed_message_get_object_path (XedMessage *message);
|
||||
const gchar *xed_message_get_method (XedMessage *message);
|
||||
|
||||
gboolean xed_message_has_key (XedMessage *message,
|
||||
const gchar *key);
|
||||
|
||||
GType xed_message_get_key_type (XedMessage *message,
|
||||
const gchar *key);
|
||||
|
||||
gboolean xed_message_validate (XedMessage *message);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_MESSAGE_H__ */
|
||||
|
||||
// ex:ts=8:noet:
|
||||
563
xed/xed-metadata-manager.c
Normal file
563
xed/xed-metadata-manager.c
Normal file
@@ -0,0 +1,563 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* xed-metadata-manager.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2003-2007 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2003-2007. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
#include "xed-metadata-manager.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-dirs.h"
|
||||
|
||||
/*
|
||||
#define XED_METADATA_VERBOSE_DEBUG 1
|
||||
*/
|
||||
|
||||
#define METADATA_FILE "xed-metadata.xml"
|
||||
|
||||
#define MAX_ITEMS 50
|
||||
|
||||
typedef struct _XedMetadataManager XedMetadataManager;
|
||||
|
||||
typedef struct _Item Item;
|
||||
|
||||
struct _Item
|
||||
{
|
||||
time_t atime; /* time of last access */
|
||||
|
||||
GHashTable *values;
|
||||
};
|
||||
|
||||
struct _XedMetadataManager
|
||||
{
|
||||
gboolean values_loaded; /* It is true if the file
|
||||
has been read */
|
||||
|
||||
guint timeout_id;
|
||||
|
||||
GHashTable *items;
|
||||
};
|
||||
|
||||
static gboolean xed_metadata_manager_save (gpointer data);
|
||||
|
||||
|
||||
static XedMetadataManager *xed_metadata_manager = NULL;
|
||||
|
||||
static void
|
||||
item_free (gpointer data)
|
||||
{
|
||||
Item *item;
|
||||
|
||||
g_return_if_fail (data != NULL);
|
||||
|
||||
#ifdef XED_METADATA_VERBOSE_DEBUG
|
||||
xed_debug (DEBUG_METADATA);
|
||||
#endif
|
||||
|
||||
item = (Item *)data;
|
||||
|
||||
if (item->values != NULL)
|
||||
g_hash_table_destroy (item->values);
|
||||
|
||||
g_free (item);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_metadata_manager_arm_timeout (void)
|
||||
{
|
||||
if (xed_metadata_manager->timeout_id == 0)
|
||||
{
|
||||
xed_metadata_manager->timeout_id =
|
||||
g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE,
|
||||
2,
|
||||
(GSourceFunc)xed_metadata_manager_save,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xed_metadata_manager_init (void)
|
||||
{
|
||||
xed_debug (DEBUG_METADATA);
|
||||
|
||||
if (xed_metadata_manager != NULL)
|
||||
return TRUE;
|
||||
|
||||
xed_metadata_manager = g_new0 (XedMetadataManager, 1);
|
||||
|
||||
xed_metadata_manager->values_loaded = FALSE;
|
||||
|
||||
xed_metadata_manager->items =
|
||||
g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
item_free);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This function must be called before exiting xed */
|
||||
void
|
||||
xed_metadata_manager_shutdown (void)
|
||||
{
|
||||
xed_debug (DEBUG_METADATA);
|
||||
|
||||
if (xed_metadata_manager == NULL)
|
||||
return;
|
||||
|
||||
if (xed_metadata_manager->timeout_id)
|
||||
{
|
||||
g_source_remove (xed_metadata_manager->timeout_id);
|
||||
xed_metadata_manager->timeout_id = 0;
|
||||
xed_metadata_manager_save (NULL);
|
||||
}
|
||||
|
||||
if (xed_metadata_manager->items != NULL)
|
||||
g_hash_table_destroy (xed_metadata_manager->items);
|
||||
|
||||
g_free (xed_metadata_manager);
|
||||
xed_metadata_manager = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
parseItem (xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
Item *item;
|
||||
|
||||
xmlChar *uri;
|
||||
xmlChar *atime;
|
||||
|
||||
#ifdef XED_METADATA_VERBOSE_DEBUG
|
||||
xed_debug (DEBUG_METADATA);
|
||||
#endif
|
||||
|
||||
if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0)
|
||||
return;
|
||||
|
||||
uri = xmlGetProp (cur, (const xmlChar *)"uri");
|
||||
if (uri == NULL)
|
||||
return;
|
||||
|
||||
atime = xmlGetProp (cur, (const xmlChar *)"atime");
|
||||
if (atime == NULL)
|
||||
{
|
||||
xmlFree (uri);
|
||||
return;
|
||||
}
|
||||
|
||||
item = g_new0 (Item, 1);
|
||||
|
||||
item->atime = g_ascii_strtoull ((char *)atime, NULL, 0);
|
||||
|
||||
item->values = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
g_free);
|
||||
|
||||
cur = cur->xmlChildrenNode;
|
||||
|
||||
while (cur != NULL)
|
||||
{
|
||||
if (xmlStrcmp (cur->name, (const xmlChar *)"entry") == 0)
|
||||
{
|
||||
xmlChar *key;
|
||||
xmlChar *value;
|
||||
|
||||
key = xmlGetProp (cur, (const xmlChar *)"key");
|
||||
value = xmlGetProp (cur, (const xmlChar *)"value");
|
||||
|
||||
if ((key != NULL) && (value != NULL))
|
||||
g_hash_table_insert (item->values,
|
||||
g_strdup ((gchar *)key),
|
||||
g_strdup ((gchar *)value));
|
||||
|
||||
if (key != NULL)
|
||||
xmlFree (key);
|
||||
if (value != NULL)
|
||||
xmlFree (value);
|
||||
}
|
||||
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
g_hash_table_insert (xed_metadata_manager->items,
|
||||
g_strdup ((gchar *)uri),
|
||||
item);
|
||||
|
||||
xmlFree (uri);
|
||||
xmlFree (atime);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
get_metadata_filename (void)
|
||||
{
|
||||
gchar *cache_dir;
|
||||
gchar *metadata;
|
||||
|
||||
cache_dir = xed_dirs_get_user_cache_dir ();
|
||||
|
||||
metadata = g_build_filename (cache_dir,
|
||||
METADATA_FILE,
|
||||
NULL);
|
||||
|
||||
g_free (cache_dir);
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_values (void)
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr cur;
|
||||
gchar *file_name;
|
||||
|
||||
xed_debug (DEBUG_METADATA);
|
||||
|
||||
g_return_val_if_fail (xed_metadata_manager != NULL, FALSE);
|
||||
g_return_val_if_fail (xed_metadata_manager->values_loaded == FALSE, FALSE);
|
||||
|
||||
xed_metadata_manager->values_loaded = TRUE;
|
||||
|
||||
xmlKeepBlanksDefault (0);
|
||||
|
||||
/* FIXME: file locking - Paolo */
|
||||
file_name = get_metadata_filename ();
|
||||
if ((file_name == NULL) ||
|
||||
(!g_file_test (file_name, G_FILE_TEST_EXISTS)))
|
||||
{
|
||||
g_free (file_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
doc = xmlParseFile (file_name);
|
||||
g_free (file_name);
|
||||
|
||||
if (doc == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cur = xmlDocGetRootElement (doc);
|
||||
if (cur == NULL)
|
||||
{
|
||||
g_message ("The metadata file '%s' is empty", METADATA_FILE);
|
||||
xmlFreeDoc (doc);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (xmlStrcmp (cur->name, (const xmlChar *) "metadata"))
|
||||
{
|
||||
g_message ("File '%s' is of the wrong type", METADATA_FILE);
|
||||
xmlFreeDoc (doc);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cur = xmlDocGetRootElement (doc);
|
||||
cur = cur->xmlChildrenNode;
|
||||
|
||||
while (cur != NULL)
|
||||
{
|
||||
parseItem (doc, cur);
|
||||
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
xmlFreeDoc (doc);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gchar *
|
||||
xed_metadata_manager_get (const gchar *uri,
|
||||
const gchar *key)
|
||||
{
|
||||
Item *item;
|
||||
gchar *value;
|
||||
|
||||
g_return_val_if_fail (uri != NULL, NULL);
|
||||
g_return_val_if_fail (key != NULL, NULL);
|
||||
|
||||
xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s", uri, key );
|
||||
|
||||
xed_metadata_manager_init ();
|
||||
|
||||
if (!xed_metadata_manager->values_loaded)
|
||||
{
|
||||
gboolean res;
|
||||
|
||||
res = load_values ();
|
||||
|
||||
if (!res)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
item = (Item *)g_hash_table_lookup (xed_metadata_manager->items,
|
||||
uri);
|
||||
|
||||
if (item == NULL)
|
||||
return NULL;
|
||||
|
||||
item->atime = time (NULL);
|
||||
|
||||
if (item->values == NULL)
|
||||
return NULL;
|
||||
|
||||
value = g_hash_table_lookup (item->values, key);
|
||||
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
else
|
||||
return g_strdup (value);
|
||||
}
|
||||
|
||||
void
|
||||
xed_metadata_manager_set (const gchar *uri,
|
||||
const gchar *key,
|
||||
const gchar *value)
|
||||
{
|
||||
Item *item;
|
||||
|
||||
g_return_if_fail (uri != NULL);
|
||||
g_return_if_fail (key != NULL);
|
||||
|
||||
xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s --- value: %s", uri, key, value);
|
||||
|
||||
xed_metadata_manager_init ();
|
||||
|
||||
if (!xed_metadata_manager->values_loaded)
|
||||
{
|
||||
gboolean res;
|
||||
|
||||
res = load_values ();
|
||||
|
||||
if (!res)
|
||||
return;
|
||||
}
|
||||
|
||||
item = (Item *)g_hash_table_lookup (xed_metadata_manager->items,
|
||||
uri);
|
||||
|
||||
if (item == NULL)
|
||||
{
|
||||
item = g_new0 (Item, 1);
|
||||
|
||||
g_hash_table_insert (xed_metadata_manager->items,
|
||||
g_strdup (uri),
|
||||
item);
|
||||
}
|
||||
|
||||
if (item->values == NULL)
|
||||
item->values = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
g_free);
|
||||
if (value != NULL)
|
||||
g_hash_table_insert (item->values,
|
||||
g_strdup (key),
|
||||
g_strdup (value));
|
||||
else
|
||||
g_hash_table_remove (item->values,
|
||||
key);
|
||||
|
||||
item->atime = time (NULL);
|
||||
|
||||
xed_metadata_manager_arm_timeout ();
|
||||
}
|
||||
|
||||
static void
|
||||
save_values (const gchar *key, const gchar *value, xmlNodePtr parent)
|
||||
{
|
||||
xmlNodePtr xml_node;
|
||||
|
||||
#ifdef XED_METADATA_VERBOSE_DEBUG
|
||||
xed_debug (DEBUG_METADATA);
|
||||
#endif
|
||||
|
||||
g_return_if_fail (key != NULL);
|
||||
|
||||
if (value == NULL)
|
||||
return;
|
||||
|
||||
xml_node = xmlNewChild (parent,
|
||||
NULL,
|
||||
(const xmlChar *)"entry",
|
||||
NULL);
|
||||
|
||||
xmlSetProp (xml_node,
|
||||
(const xmlChar *)"key",
|
||||
(const xmlChar *)key);
|
||||
xmlSetProp (xml_node,
|
||||
(const xmlChar *)"value",
|
||||
(const xmlChar *)value);
|
||||
|
||||
#ifdef XED_METADATA_VERBOSE_DEBUG
|
||||
xed_debug_message (DEBUG_METADATA, "entry: %s = %s", key, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
save_item (const gchar *key, const gpointer *data, xmlNodePtr parent)
|
||||
{
|
||||
xmlNodePtr xml_node;
|
||||
const Item *item = (const Item *)data;
|
||||
gchar *atime;
|
||||
|
||||
#ifdef XED_METADATA_VERBOSE_DEBUG
|
||||
xed_debug (DEBUG_METADATA);
|
||||
#endif
|
||||
|
||||
g_return_if_fail (key != NULL);
|
||||
|
||||
if (item == NULL)
|
||||
return;
|
||||
|
||||
xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"document", NULL);
|
||||
|
||||
xmlSetProp (xml_node, (const xmlChar *)"uri", (const xmlChar *)key);
|
||||
|
||||
#ifdef XED_METADATA_VERBOSE_DEBUG
|
||||
xed_debug_message (DEBUG_METADATA, "uri: %s", key);
|
||||
#endif
|
||||
|
||||
atime = g_strdup_printf ("%ld", item->atime);
|
||||
xmlSetProp (xml_node, (const xmlChar *)"atime", (const xmlChar *)atime);
|
||||
|
||||
#ifdef XED_METADATA_VERBOSE_DEBUG
|
||||
xed_debug_message (DEBUG_METADATA, "atime: %s", atime);
|
||||
#endif
|
||||
|
||||
g_free (atime);
|
||||
|
||||
g_hash_table_foreach (item->values,
|
||||
(GHFunc)save_values,
|
||||
xml_node);
|
||||
}
|
||||
|
||||
static void
|
||||
get_oldest (const gchar *key, const gpointer value, const gchar ** key_to_remove)
|
||||
{
|
||||
const Item *item = (const Item *)value;
|
||||
|
||||
if (*key_to_remove == NULL)
|
||||
{
|
||||
*key_to_remove = key;
|
||||
}
|
||||
else
|
||||
{
|
||||
const Item *item_to_remove =
|
||||
g_hash_table_lookup (xed_metadata_manager->items,
|
||||
*key_to_remove);
|
||||
|
||||
g_return_if_fail (item_to_remove != NULL);
|
||||
|
||||
if (item->atime < item_to_remove->atime)
|
||||
{
|
||||
*key_to_remove = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
resize_items (void)
|
||||
{
|
||||
while (g_hash_table_size (xed_metadata_manager->items) > MAX_ITEMS)
|
||||
{
|
||||
gpointer key_to_remove = NULL;
|
||||
|
||||
g_hash_table_foreach (xed_metadata_manager->items,
|
||||
(GHFunc)get_oldest,
|
||||
&key_to_remove);
|
||||
|
||||
g_return_if_fail (key_to_remove != NULL);
|
||||
|
||||
g_hash_table_remove (xed_metadata_manager->items,
|
||||
key_to_remove);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xed_metadata_manager_save (gpointer data)
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr root;
|
||||
gchar *file_name;
|
||||
|
||||
xed_debug (DEBUG_METADATA);
|
||||
|
||||
xed_metadata_manager->timeout_id = 0;
|
||||
|
||||
resize_items ();
|
||||
|
||||
xmlIndentTreeOutput = TRUE;
|
||||
|
||||
doc = xmlNewDoc ((const xmlChar *)"1.0");
|
||||
if (doc == NULL)
|
||||
return TRUE;
|
||||
|
||||
/* Create metadata root */
|
||||
root = xmlNewDocNode (doc, NULL, (const xmlChar *)"metadata", NULL);
|
||||
xmlDocSetRootElement (doc, root);
|
||||
|
||||
g_hash_table_foreach (xed_metadata_manager->items,
|
||||
(GHFunc)save_item,
|
||||
root);
|
||||
|
||||
/* FIXME: lock file - Paolo */
|
||||
file_name = get_metadata_filename ();
|
||||
if (file_name != NULL)
|
||||
{
|
||||
gchar *cache_dir;
|
||||
int res;
|
||||
|
||||
/* make sure the cache dir exists */
|
||||
cache_dir = xed_dirs_get_user_cache_dir ();
|
||||
res = g_mkdir_with_parents (cache_dir, 0755);
|
||||
if (res != -1)
|
||||
{
|
||||
xmlSaveFormatFile (file_name, doc, 1);
|
||||
}
|
||||
|
||||
g_free (cache_dir);
|
||||
g_free (file_name);
|
||||
}
|
||||
|
||||
xmlFreeDoc (doc);
|
||||
|
||||
xed_debug_message (DEBUG_METADATA, "DONE");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
50
xed/xed-metadata-manager.h
Normal file
50
xed/xed-metadata-manager.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* xed-metadata-manager.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2003 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2003. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*/
|
||||
|
||||
#ifndef __XED_METADATA_MANAGER_H__
|
||||
#define __XED_METADATA_MANAGER_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
/* This function must be called before exiting xed */
|
||||
void xed_metadata_manager_shutdown (void);
|
||||
|
||||
|
||||
gchar *xed_metadata_manager_get (const gchar *uri,
|
||||
const gchar *key);
|
||||
void xed_metadata_manager_set (const gchar *uri,
|
||||
const gchar *key,
|
||||
const gchar *value);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_METADATA_MANAGER_H__ */
|
||||
1092
xed/xed-notebook.c
Normal file
1092
xed/xed-notebook.c
Normal file
File diff suppressed because it is too large
Load Diff
143
xed/xed-notebook.h
Normal file
143
xed/xed-notebook.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* xed-notebook.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*/
|
||||
|
||||
/* This file is a modified version of the epiphany file ephy-notebook.h
|
||||
* Here the relevant copyright:
|
||||
*
|
||||
* Copyright (C) 2002 Christophe Fergeau
|
||||
* Copyright (C) 2003 Marco Pesenti Gritti
|
||||
* Copyright (C) 2003, 2004 Christian Persch
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef XED_NOTEBOOK_H
|
||||
#define XED_NOTEBOOK_H
|
||||
|
||||
#include <xed/xed-tab.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_NOTEBOOK (xed_notebook_get_type ())
|
||||
#define XED_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), XED_TYPE_NOTEBOOK, XedNotebook))
|
||||
#define XED_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), XED_TYPE_NOTEBOOK, XedNotebookClass))
|
||||
#define XED_IS_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), XED_TYPE_NOTEBOOK))
|
||||
#define XED_IS_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), XED_TYPE_NOTEBOOK))
|
||||
#define XED_NOTEBOOK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), XED_TYPE_NOTEBOOK, XedNotebookClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedNotebookPrivate XedNotebookPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedNotebook XedNotebook;
|
||||
|
||||
struct _XedNotebook
|
||||
{
|
||||
GtkNotebook notebook;
|
||||
|
||||
/*< private >*/
|
||||
XedNotebookPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedNotebookClass XedNotebookClass;
|
||||
|
||||
struct _XedNotebookClass
|
||||
{
|
||||
GtkNotebookClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (* tab_added) (XedNotebook *notebook,
|
||||
XedTab *tab);
|
||||
void (* tab_removed) (XedNotebook *notebook,
|
||||
XedTab *tab);
|
||||
void (* tab_detached) (XedNotebook *notebook,
|
||||
XedTab *tab);
|
||||
void (* tabs_reordered) (XedNotebook *notebook);
|
||||
void (* tab_close_request)
|
||||
(XedNotebook *notebook,
|
||||
XedTab *tab);
|
||||
};
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_notebook_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget *xed_notebook_new (void);
|
||||
|
||||
void xed_notebook_add_tab (XedNotebook *nb,
|
||||
XedTab *tab,
|
||||
gint position,
|
||||
gboolean jump_to);
|
||||
|
||||
void xed_notebook_remove_tab (XedNotebook *nb,
|
||||
XedTab *tab);
|
||||
|
||||
void xed_notebook_remove_all_tabs (XedNotebook *nb);
|
||||
|
||||
void xed_notebook_reorder_tab (XedNotebook *src,
|
||||
XedTab *tab,
|
||||
gint dest_position);
|
||||
|
||||
void xed_notebook_move_tab (XedNotebook *src,
|
||||
XedNotebook *dest,
|
||||
XedTab *tab,
|
||||
gint dest_position);
|
||||
|
||||
/* FIXME: do we really need this function ? */
|
||||
void xed_notebook_set_always_show_tabs
|
||||
(XedNotebook *nb,
|
||||
gboolean show_tabs);
|
||||
|
||||
void xed_notebook_set_close_buttons_sensitive
|
||||
(XedNotebook *nb,
|
||||
gboolean sensitive);
|
||||
|
||||
gboolean xed_notebook_get_close_buttons_sensitive
|
||||
(XedNotebook *nb);
|
||||
|
||||
void xed_notebook_set_tab_drag_and_drop_enabled
|
||||
(XedNotebook *nb,
|
||||
gboolean enable);
|
||||
|
||||
gboolean xed_notebook_get_tab_drag_and_drop_enabled
|
||||
(XedNotebook *nb);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* XED_NOTEBOOK_H */
|
||||
343
xed/xed-object-module.c
Normal file
343
xed/xed-object-module.c
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* xed-object-module.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
* Copyright (C) 2008 - Jesse van den Kieboom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* This is a modified version of ephy-module.c from Epiphany source code.
|
||||
* Here the original copyright assignment:
|
||||
*
|
||||
* Copyright (C) 2003 Marco Pesenti Gritti
|
||||
* Copyright (C) 2003, 2004 Christian Persch
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id: xed-module.c 6314 2008-06-05 12:57:53Z pborelli $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "xed-object-module.h"
|
||||
#include "xed-debug.h"
|
||||
|
||||
typedef GType (*XedObjectModuleRegisterFunc) (GTypeModule *);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_MODULE_NAME,
|
||||
PROP_PATH,
|
||||
PROP_TYPE_REGISTRATION,
|
||||
PROP_RESIDENT
|
||||
};
|
||||
|
||||
struct _XedObjectModulePrivate
|
||||
{
|
||||
GModule *library;
|
||||
|
||||
GType type;
|
||||
gchar *path;
|
||||
gchar *module_name;
|
||||
gchar *type_registration;
|
||||
|
||||
gboolean resident;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (XedObjectModule, xed_object_module, G_TYPE_TYPE_MODULE);
|
||||
|
||||
static gboolean
|
||||
xed_object_module_load (GTypeModule *gmodule)
|
||||
{
|
||||
XedObjectModule *module = XED_OBJECT_MODULE (gmodule);
|
||||
XedObjectModuleRegisterFunc register_func;
|
||||
gchar *path;
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "Loading %s module from %s",
|
||||
module->priv->module_name, module->priv->path);
|
||||
|
||||
path = g_module_build_path (module->priv->path, module->priv->module_name);
|
||||
g_return_val_if_fail (path != NULL, FALSE);
|
||||
xed_debug_message (DEBUG_PLUGINS, "Module filename: %s", path);
|
||||
|
||||
module->priv->library = g_module_open (path,
|
||||
G_MODULE_BIND_LAZY);
|
||||
g_free (path);
|
||||
|
||||
if (module->priv->library == NULL)
|
||||
{
|
||||
g_warning ("%s: %s", module->priv->module_name, g_module_error());
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* extract symbols from the lib */
|
||||
if (!g_module_symbol (module->priv->library, module->priv->type_registration,
|
||||
(void *) ®ister_func))
|
||||
{
|
||||
g_warning ("%s: %s", module->priv->module_name, g_module_error());
|
||||
g_module_close (module->priv->library);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* symbol can still be NULL even though g_module_symbol
|
||||
* returned TRUE */
|
||||
if (register_func == NULL)
|
||||
{
|
||||
g_warning ("Symbol '%s' should not be NULL", module->priv->type_registration);
|
||||
g_module_close (module->priv->library);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
module->priv->type = register_func (gmodule);
|
||||
|
||||
if (module->priv->type == 0)
|
||||
{
|
||||
g_warning ("Invalid object contained by module %s", module->priv->module_name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (module->priv->resident)
|
||||
{
|
||||
g_module_make_resident (module->priv->library);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
xed_object_module_unload (GTypeModule *gmodule)
|
||||
{
|
||||
XedObjectModule *module = XED_OBJECT_MODULE (gmodule);
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "Unloading %s", module->priv->path);
|
||||
|
||||
g_module_close (module->priv->library);
|
||||
|
||||
module->priv->library = NULL;
|
||||
module->priv->type = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
xed_object_module_init (XedObjectModule *module)
|
||||
{
|
||||
xed_debug_message (DEBUG_PLUGINS, "XedObjectModule %p initialising", module);
|
||||
|
||||
module->priv = G_TYPE_INSTANCE_GET_PRIVATE (module,
|
||||
XED_TYPE_OBJECT_MODULE,
|
||||
XedObjectModulePrivate);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_object_module_finalize (GObject *object)
|
||||
{
|
||||
XedObjectModule *module = XED_OBJECT_MODULE (object);
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "XedObjectModule %p finalising", module);
|
||||
|
||||
g_free (module->priv->path);
|
||||
g_free (module->priv->module_name);
|
||||
g_free (module->priv->type_registration);
|
||||
|
||||
G_OBJECT_CLASS (xed_object_module_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_object_module_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedObjectModule *module = XED_OBJECT_MODULE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODULE_NAME:
|
||||
g_value_set_string (value, module->priv->module_name);
|
||||
break;
|
||||
case PROP_PATH:
|
||||
g_value_set_string (value, module->priv->path);
|
||||
break;
|
||||
case PROP_TYPE_REGISTRATION:
|
||||
g_value_set_string (value, module->priv->type_registration);
|
||||
break;
|
||||
case PROP_RESIDENT:
|
||||
g_value_set_boolean (value, module->priv->resident);
|
||||
break;
|
||||
default:
|
||||
g_return_if_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_object_module_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedObjectModule *module = XED_OBJECT_MODULE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODULE_NAME:
|
||||
module->priv->module_name = g_value_dup_string (value);
|
||||
g_type_module_set_name (G_TYPE_MODULE (object),
|
||||
module->priv->module_name);
|
||||
break;
|
||||
case PROP_PATH:
|
||||
module->priv->path = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_TYPE_REGISTRATION:
|
||||
module->priv->type_registration = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_RESIDENT:
|
||||
module->priv->resident = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
g_return_if_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_object_module_class_init (XedObjectModuleClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (klass);
|
||||
|
||||
object_class->set_property = xed_object_module_set_property;
|
||||
object_class->get_property = xed_object_module_get_property;
|
||||
object_class->finalize = xed_object_module_finalize;
|
||||
|
||||
module_class->load = xed_object_module_load;
|
||||
module_class->unload = xed_object_module_unload;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_MODULE_NAME,
|
||||
g_param_spec_string ("module-name",
|
||||
"Module Name",
|
||||
"The module to load for this object",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_PATH,
|
||||
g_param_spec_string ("path",
|
||||
"Path",
|
||||
"The path to use when loading this module",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_TYPE_REGISTRATION,
|
||||
g_param_spec_string ("type-registration",
|
||||
"Type Registration",
|
||||
"The name of the type registration function",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_RESIDENT,
|
||||
g_param_spec_boolean ("resident",
|
||||
"Resident",
|
||||
"Whether the module is resident",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_type_class_add_private (klass, sizeof (XedObjectModulePrivate));
|
||||
}
|
||||
|
||||
XedObjectModule *
|
||||
xed_object_module_new (const gchar *module_name,
|
||||
const gchar *path,
|
||||
const gchar *type_registration,
|
||||
gboolean resident)
|
||||
{
|
||||
return (XedObjectModule *)g_object_new (XED_TYPE_OBJECT_MODULE,
|
||||
"module-name",
|
||||
module_name,
|
||||
"path",
|
||||
path,
|
||||
"type-registration",
|
||||
type_registration,
|
||||
"resident",
|
||||
resident,
|
||||
NULL);
|
||||
}
|
||||
|
||||
GObject *
|
||||
xed_object_module_new_object (XedObjectModule *module,
|
||||
const gchar *first_property_name,
|
||||
...)
|
||||
{
|
||||
va_list var_args;
|
||||
GObject *result;
|
||||
|
||||
g_return_val_if_fail (module->priv->type != 0, NULL);
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "Creating object of type %s",
|
||||
g_type_name (module->priv->type));
|
||||
|
||||
va_start (var_args, first_property_name);
|
||||
result = g_object_new_valist (module->priv->type, first_property_name, var_args);
|
||||
va_end (var_args);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_object_module_get_path (XedObjectModule *module)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_OBJECT_MODULE (module), NULL);
|
||||
|
||||
return module->priv->path;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_object_module_get_module_name (XedObjectModule *module)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_OBJECT_MODULE (module), NULL);
|
||||
|
||||
return module->priv->module_name;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_object_module_get_type_registration (XedObjectModule *module)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_OBJECT_MODULE (module), NULL);
|
||||
|
||||
return module->priv->type_registration;
|
||||
}
|
||||
|
||||
GType
|
||||
xed_object_module_get_object_type (XedObjectModule *module)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_OBJECT_MODULE (module), 0);
|
||||
|
||||
return module->priv->type;
|
||||
}
|
||||
94
xed/xed-object-module.h
Normal file
94
xed/xed-object-module.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* xed-object-module.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
* Copyright (C) 2008 - Jesse van den Kieboom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* This is a modified version of xed-module.h from Epiphany source code.
|
||||
* Here the original copyright assignment:
|
||||
*
|
||||
* Copyright (C) 2003 Marco Pesenti Gritti
|
||||
* Copyright (C) 2003, 2004 Christian Persch
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id: xed-module.h 6263 2008-05-05 10:52:10Z sfre $
|
||||
*/
|
||||
|
||||
#ifndef __XED_OBJECT_MODULE_H__
|
||||
#define __XED_OBJECT_MODULE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gmodule.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_OBJECT_MODULE (xed_object_module_get_type ())
|
||||
#define XED_OBJECT_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_OBJECT_MODULE, XedObjectModule))
|
||||
#define XED_OBJECT_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_OBJECT_MODULE, XedObjectModuleClass))
|
||||
#define XED_IS_OBJECT_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_OBJECT_MODULE))
|
||||
#define XED_IS_OBJECT_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_OBJECT_MODULE))
|
||||
#define XED_OBJECT_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_OBJECT_MODULE, XedObjectModuleClass))
|
||||
|
||||
typedef struct _XedObjectModule XedObjectModule;
|
||||
typedef struct _XedObjectModulePrivate XedObjectModulePrivate;
|
||||
|
||||
struct _XedObjectModule
|
||||
{
|
||||
GTypeModule parent;
|
||||
|
||||
XedObjectModulePrivate *priv;
|
||||
};
|
||||
|
||||
typedef struct _XedObjectModuleClass XedObjectModuleClass;
|
||||
|
||||
struct _XedObjectModuleClass
|
||||
{
|
||||
GTypeModuleClass parent_class;
|
||||
|
||||
/* Virtual class methods */
|
||||
void (* garbage_collect) ();
|
||||
};
|
||||
|
||||
GType xed_object_module_get_type (void) G_GNUC_CONST;
|
||||
|
||||
XedObjectModule *xed_object_module_new (const gchar *module_name,
|
||||
const gchar *path,
|
||||
const gchar *type_registration,
|
||||
gboolean resident);
|
||||
|
||||
GObject *xed_object_module_new_object (XedObjectModule *module,
|
||||
const gchar *first_property_name,
|
||||
...);
|
||||
|
||||
GType xed_object_module_get_object_type (XedObjectModule *module);
|
||||
const gchar *xed_object_module_get_path (XedObjectModule *module);
|
||||
const gchar *xed_object_module_get_module_name (XedObjectModule *module);
|
||||
const gchar *xed_object_module_get_type_registration (XedObjectModule *module);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
986
xed/xed-panel.c
Normal file
986
xed/xed-panel.c
Normal file
@@ -0,0 +1,986 @@
|
||||
/*
|
||||
* xed-panel.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "xed-panel.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include "xed-close-button.h"
|
||||
#include "xed-window.h"
|
||||
#include "xed-debug.h"
|
||||
|
||||
#define PANEL_ITEM_KEY "XedPanelItemKey"
|
||||
|
||||
#define XED_PANEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_PANEL, XedPanelPrivate))
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
#define gtk_hbox_new(X,Y) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,Y)
|
||||
#define gtk_vbox_new(X,Y) gtk_box_new(GTK_ORIENTATION_VERTICAL,Y)
|
||||
#endif
|
||||
|
||||
struct _XedPanelPrivate
|
||||
{
|
||||
GtkOrientation orientation;
|
||||
|
||||
/* Title bar (vertical panel only) */
|
||||
GtkWidget *title_image;
|
||||
GtkWidget *title_label;
|
||||
|
||||
/* Notebook */
|
||||
GtkWidget *notebook;
|
||||
};
|
||||
|
||||
typedef struct _XedPanelItem XedPanelItem;
|
||||
|
||||
struct _XedPanelItem
|
||||
{
|
||||
gchar *name;
|
||||
GtkWidget *icon;
|
||||
};
|
||||
|
||||
/* Properties */
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ORIENTATION
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum {
|
||||
ITEM_ADDED,
|
||||
ITEM_REMOVED,
|
||||
CLOSE,
|
||||
FOCUS_DOCUMENT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static GObject *xed_panel_constructor (GType type,
|
||||
guint n_construct_properties,
|
||||
GObjectConstructParam *construct_properties);
|
||||
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
G_DEFINE_TYPE(XedPanel, xed_panel, GTK_TYPE_BOX)
|
||||
#else
|
||||
G_DEFINE_TYPE(XedPanel, xed_panel, GTK_TYPE_VBOX)
|
||||
#endif
|
||||
|
||||
static void
|
||||
xed_panel_finalize (GObject *obj)
|
||||
{
|
||||
if (G_OBJECT_CLASS (xed_panel_parent_class)->finalize)
|
||||
(*G_OBJECT_CLASS (xed_panel_parent_class)->finalize) (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_panel_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedPanel *panel = XED_PANEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ORIENTATION:
|
||||
g_value_set_enum(value, panel->priv->orientation);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_panel_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedPanel *panel = XED_PANEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ORIENTATION:
|
||||
panel->priv->orientation = g_value_get_enum (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_panel_close (XedPanel *panel)
|
||||
{
|
||||
gtk_widget_hide (GTK_WIDGET (panel));
|
||||
}
|
||||
|
||||
static void
|
||||
xed_panel_focus_document (XedPanel *panel)
|
||||
{
|
||||
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (panel));
|
||||
if (gtk_widget_is_toplevel (toplevel) && XED_IS_WINDOW (toplevel))
|
||||
{
|
||||
XedView *view;
|
||||
|
||||
view = xed_window_get_active_view (XED_WINDOW (toplevel));
|
||||
if (view != NULL)
|
||||
gtk_widget_grab_focus (GTK_WIDGET (view));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_panel_grab_focus (GtkWidget *w)
|
||||
{
|
||||
gint n;
|
||||
GtkWidget *tab;
|
||||
XedPanel *panel = XED_PANEL (w);
|
||||
|
||||
n = gtk_notebook_get_current_page (GTK_NOTEBOOK (panel->priv->notebook));
|
||||
if (n == -1)
|
||||
return;
|
||||
|
||||
tab = gtk_notebook_get_nth_page (GTK_NOTEBOOK (panel->priv->notebook),
|
||||
n);
|
||||
g_return_if_fail (tab != NULL);
|
||||
|
||||
gtk_widget_grab_focus (tab);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_panel_class_init (XedPanelClass *klass)
|
||||
{
|
||||
GtkBindingSet *binding_set;
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (XedPanelPrivate));
|
||||
|
||||
object_class->constructor = xed_panel_constructor;
|
||||
object_class->finalize = xed_panel_finalize;
|
||||
object_class->get_property = xed_panel_get_property;
|
||||
object_class->set_property = xed_panel_set_property;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_ORIENTATION,
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
g_param_spec_enum ("panel-orientation",
|
||||
"Panel Orientation",
|
||||
#else
|
||||
g_param_spec_enum ("orientation",
|
||||
"Orientation",
|
||||
#endif
|
||||
"The panel's orientation",
|
||||
GTK_TYPE_ORIENTATION,
|
||||
GTK_ORIENTATION_VERTICAL,
|
||||
G_PARAM_WRITABLE |
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
widget_class->grab_focus = xed_panel_grab_focus;
|
||||
|
||||
klass->close = xed_panel_close;
|
||||
klass->focus_document = xed_panel_focus_document;
|
||||
|
||||
signals[ITEM_ADDED] =
|
||||
g_signal_new ("item_added",
|
||||
G_OBJECT_CLASS_TYPE (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (XedPanelClass, item_added),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
GTK_TYPE_WIDGET);
|
||||
signals[ITEM_REMOVED] =
|
||||
g_signal_new ("item_removed",
|
||||
G_OBJECT_CLASS_TYPE (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (XedPanelClass, item_removed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
GTK_TYPE_WIDGET);
|
||||
|
||||
/* Keybinding signals */
|
||||
signals[CLOSE] =
|
||||
g_signal_new ("close",
|
||||
G_OBJECT_CLASS_TYPE (klass),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
G_STRUCT_OFFSET (XedPanelClass, close),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
signals[FOCUS_DOCUMENT] =
|
||||
g_signal_new ("focus_document",
|
||||
G_OBJECT_CLASS_TYPE (klass),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
G_STRUCT_OFFSET (XedPanelClass, focus_document),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
binding_set = gtk_binding_set_by_class (klass);
|
||||
|
||||
gtk_binding_entry_add_signal (binding_set,
|
||||
GDK_KEY_Escape,
|
||||
0,
|
||||
"close",
|
||||
0);
|
||||
gtk_binding_entry_add_signal (binding_set,
|
||||
GDK_KEY_Return,
|
||||
GDK_CONTROL_MASK,
|
||||
"focus_document",
|
||||
0);
|
||||
}
|
||||
|
||||
/* This is ugly, since it supports only known
|
||||
* storage types of GtkImage, otherwise fall back
|
||||
* to the empty icon.
|
||||
* See http://bugzilla.gnome.org/show_bug.cgi?id=317520.
|
||||
*/
|
||||
static void
|
||||
set_gtk_image_from_gtk_image (GtkImage *image,
|
||||
GtkImage *source)
|
||||
{
|
||||
switch (gtk_image_get_storage_type (source))
|
||||
{
|
||||
case GTK_IMAGE_EMPTY:
|
||||
gtk_image_clear (image);
|
||||
break;
|
||||
#if !GTK_CHECK_VERSION (3, 0, 0)
|
||||
case GTK_IMAGE_PIXMAP:
|
||||
{
|
||||
GdkPixmap *pm;
|
||||
GdkBitmap *bm;
|
||||
|
||||
gtk_image_get_pixmap (source, &pm, &bm);
|
||||
gtk_image_set_from_pixmap (image, pm, bm);
|
||||
}
|
||||
break;
|
||||
case GTK_IMAGE_IMAGE:
|
||||
{
|
||||
GdkImage *i;
|
||||
GdkBitmap *bm;
|
||||
|
||||
gtk_image_get_image (source, &i, &bm);
|
||||
gtk_image_set_from_image (image, i, bm);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case GTK_IMAGE_PIXBUF:
|
||||
{
|
||||
GdkPixbuf *pb;
|
||||
|
||||
pb = gtk_image_get_pixbuf (source);
|
||||
gtk_image_set_from_pixbuf (image, pb);
|
||||
}
|
||||
break;
|
||||
case GTK_IMAGE_STOCK:
|
||||
{
|
||||
gchar *s_id;
|
||||
GtkIconSize s;
|
||||
|
||||
gtk_image_get_stock (source, &s_id, &s);
|
||||
gtk_image_set_from_stock (image, s_id, s);
|
||||
}
|
||||
break;
|
||||
case GTK_IMAGE_ICON_SET:
|
||||
{
|
||||
GtkIconSet *is;
|
||||
GtkIconSize s;
|
||||
|
||||
gtk_image_get_icon_set (source, &is, &s);
|
||||
gtk_image_set_from_icon_set (image, is, s);
|
||||
}
|
||||
break;
|
||||
case GTK_IMAGE_ANIMATION:
|
||||
{
|
||||
GdkPixbufAnimation *a;
|
||||
|
||||
a = gtk_image_get_animation (source);
|
||||
gtk_image_set_from_animation (image, a);
|
||||
}
|
||||
break;
|
||||
case GTK_IMAGE_ICON_NAME:
|
||||
{
|
||||
const gchar *n;
|
||||
GtkIconSize s;
|
||||
|
||||
gtk_image_get_icon_name (source, &n, &s);
|
||||
gtk_image_set_from_icon_name (image, n, s);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
gtk_image_set_from_stock (image,
|
||||
GTK_STOCK_FILE,
|
||||
GTK_ICON_SIZE_MENU);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sync_title (XedPanel *panel,
|
||||
XedPanelItem *item)
|
||||
{
|
||||
if (panel->priv->orientation != GTK_ORIENTATION_VERTICAL)
|
||||
return;
|
||||
|
||||
if (item != NULL)
|
||||
{
|
||||
gtk_label_set_text (GTK_LABEL (panel->priv->title_label),
|
||||
item->name);
|
||||
|
||||
set_gtk_image_from_gtk_image (GTK_IMAGE (panel->priv->title_image),
|
||||
GTK_IMAGE (item->icon));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_label_set_text (GTK_LABEL (panel->priv->title_label),
|
||||
_("Empty"));
|
||||
|
||||
gtk_image_set_from_stock (GTK_IMAGE (panel->priv->title_image),
|
||||
GTK_STOCK_FILE,
|
||||
GTK_ICON_SIZE_MENU);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
notebook_page_changed (GtkNotebook *notebook,
|
||||
GtkWidget *page,
|
||||
guint page_num,
|
||||
XedPanel *panel)
|
||||
{
|
||||
GtkWidget *item;
|
||||
XedPanelItem *data;
|
||||
|
||||
item = gtk_notebook_get_nth_page (notebook, page_num);
|
||||
g_return_if_fail (item != NULL);
|
||||
|
||||
data = (XedPanelItem *)g_object_get_data (G_OBJECT (item),
|
||||
PANEL_ITEM_KEY);
|
||||
g_return_if_fail (data != NULL);
|
||||
|
||||
sync_title (panel, data);
|
||||
}
|
||||
|
||||
static void
|
||||
panel_show (XedPanel *panel,
|
||||
gpointer user_data)
|
||||
{
|
||||
gint page;
|
||||
GtkNotebook *nb;
|
||||
|
||||
nb = GTK_NOTEBOOK (panel->priv->notebook);
|
||||
|
||||
page = gtk_notebook_get_current_page (nb);
|
||||
|
||||
if (page != -1)
|
||||
notebook_page_changed (nb, NULL, page, panel);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_panel_init (XedPanel *panel)
|
||||
{
|
||||
panel->priv = XED_PANEL_GET_PRIVATE (panel);
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (panel),
|
||||
GTK_ORIENTATION_VERTICAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
close_button_clicked_cb (GtkWidget *widget,
|
||||
GtkWidget *panel)
|
||||
{
|
||||
gtk_widget_hide (panel);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_close_button (XedPanel *panel)
|
||||
{
|
||||
GtkWidget *button;
|
||||
|
||||
button = xed_close_button_new ();
|
||||
|
||||
gtk_widget_set_tooltip_text (button, _("Hide panel"));
|
||||
|
||||
g_signal_connect (button,
|
||||
"clicked",
|
||||
G_CALLBACK (close_button_clicked_cb),
|
||||
panel);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
static void
|
||||
build_notebook_for_panel (XedPanel *panel)
|
||||
{
|
||||
/* Create the panel notebook */
|
||||
panel->priv->notebook = gtk_notebook_new ();
|
||||
|
||||
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (panel->priv->notebook),
|
||||
GTK_POS_BOTTOM);
|
||||
gtk_notebook_set_scrollable (GTK_NOTEBOOK (panel->priv->notebook),
|
||||
TRUE);
|
||||
gtk_notebook_popup_enable (GTK_NOTEBOOK (panel->priv->notebook));
|
||||
|
||||
gtk_widget_show (GTK_WIDGET (panel->priv->notebook));
|
||||
|
||||
g_signal_connect (panel->priv->notebook,
|
||||
"switch-page",
|
||||
G_CALLBACK (notebook_page_changed),
|
||||
panel);
|
||||
}
|
||||
|
||||
static void
|
||||
build_horizontal_panel (XedPanel *panel)
|
||||
{
|
||||
GtkWidget *box;
|
||||
GtkWidget *sidebar;
|
||||
GtkWidget *close_button;
|
||||
|
||||
box = gtk_hbox_new(FALSE, 0);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (box),
|
||||
panel->priv->notebook,
|
||||
TRUE,
|
||||
TRUE,
|
||||
0);
|
||||
|
||||
/* Toolbar, close button and first separator */
|
||||
sidebar = gtk_vbox_new(FALSE, 6);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (sidebar), 4);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (box),
|
||||
sidebar,
|
||||
FALSE,
|
||||
FALSE,
|
||||
0);
|
||||
|
||||
close_button = create_close_button (panel);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (sidebar),
|
||||
close_button,
|
||||
FALSE,
|
||||
FALSE,
|
||||
0);
|
||||
|
||||
gtk_widget_show_all (box);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (panel),
|
||||
box,
|
||||
TRUE,
|
||||
TRUE,
|
||||
0);
|
||||
}
|
||||
|
||||
static void
|
||||
build_vertical_panel (XedPanel *panel)
|
||||
{
|
||||
GtkWidget *close_button;
|
||||
GtkWidget *title_hbox;
|
||||
GtkWidget *icon_name_hbox;
|
||||
GtkWidget *dummy_label;
|
||||
|
||||
/* Create title hbox */
|
||||
title_hbox = gtk_hbox_new (FALSE, 6);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (title_hbox), 5);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (panel), title_hbox, FALSE, FALSE, 0);
|
||||
|
||||
icon_name_hbox = gtk_hbox_new (FALSE, 0);
|
||||
gtk_box_pack_start (GTK_BOX (title_hbox),
|
||||
icon_name_hbox,
|
||||
TRUE,
|
||||
TRUE,
|
||||
0);
|
||||
|
||||
panel->priv->title_image =
|
||||
gtk_image_new_from_stock (GTK_STOCK_FILE,
|
||||
GTK_ICON_SIZE_MENU);
|
||||
gtk_box_pack_start (GTK_BOX (icon_name_hbox),
|
||||
panel->priv->title_image,
|
||||
FALSE,
|
||||
TRUE,
|
||||
0);
|
||||
|
||||
dummy_label = gtk_label_new (" ");
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (icon_name_hbox),
|
||||
dummy_label,
|
||||
FALSE,
|
||||
FALSE,
|
||||
0);
|
||||
|
||||
panel->priv->title_label = gtk_label_new (_("Empty"));
|
||||
#if GTK_CHECK_VERSION (3, 16, 0)
|
||||
gtk_label_set_xalign (GTK_LABEL (panel->priv->title_label), 0.0);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (panel->priv->title_label), 0, 0.5);
|
||||
#endif
|
||||
gtk_label_set_ellipsize(GTK_LABEL (panel->priv->title_label), PANGO_ELLIPSIZE_END);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (icon_name_hbox),
|
||||
panel->priv->title_label,
|
||||
TRUE,
|
||||
TRUE,
|
||||
0);
|
||||
|
||||
close_button = create_close_button (panel);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (title_hbox),
|
||||
close_button,
|
||||
FALSE,
|
||||
FALSE,
|
||||
0);
|
||||
|
||||
gtk_widget_show_all (title_hbox);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (panel),
|
||||
panel->priv->notebook,
|
||||
TRUE,
|
||||
TRUE,
|
||||
0);
|
||||
}
|
||||
|
||||
static GObject *
|
||||
xed_panel_constructor (GType type,
|
||||
guint n_construct_properties,
|
||||
GObjectConstructParam *construct_properties)
|
||||
{
|
||||
|
||||
/* Invoke parent constructor. */
|
||||
XedPanelClass *klass = XED_PANEL_CLASS (g_type_class_peek (XED_TYPE_PANEL));
|
||||
GObjectClass *parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
|
||||
GObject *obj = parent_class->constructor (type,
|
||||
n_construct_properties,
|
||||
construct_properties);
|
||||
|
||||
/* Build the panel, now that we know the orientation
|
||||
(_init has been called previously) */
|
||||
XedPanel *panel = XED_PANEL (obj);
|
||||
|
||||
build_notebook_for_panel (panel);
|
||||
if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
build_horizontal_panel (panel);
|
||||
else
|
||||
build_vertical_panel (panel);
|
||||
|
||||
g_signal_connect (panel,
|
||||
"show",
|
||||
G_CALLBACK (panel_show),
|
||||
NULL);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_panel_new:
|
||||
* @orientation: a #GtkOrientation
|
||||
*
|
||||
* Creates a new #XedPanel with the given @orientation. You shouldn't create
|
||||
* a new panel use xed_window_get_side_panel() or xed_window_get_bottom_panel()
|
||||
* instead.
|
||||
*
|
||||
* Returns: a new #XedPanel object.
|
||||
*/
|
||||
GtkWidget *
|
||||
xed_panel_new (GtkOrientation orientation)
|
||||
{
|
||||
return GTK_WIDGET (g_object_new (XED_TYPE_PANEL, "orientation", orientation, NULL));
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
build_tab_label (XedPanel *panel,
|
||||
GtkWidget *item,
|
||||
const gchar *name,
|
||||
GtkWidget *icon)
|
||||
{
|
||||
GtkWidget *hbox, *label_hbox, *label_ebox;
|
||||
GtkWidget *label;
|
||||
|
||||
/* set hbox spacing and label padding (see below) so that there's an
|
||||
* equal amount of space around the label */
|
||||
hbox = gtk_hbox_new (FALSE, 4);
|
||||
|
||||
label_ebox = gtk_event_box_new ();
|
||||
gtk_event_box_set_visible_window (GTK_EVENT_BOX (label_ebox), FALSE);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), label_ebox, TRUE, TRUE, 0);
|
||||
|
||||
label_hbox = gtk_hbox_new (FALSE, 4);
|
||||
gtk_container_add (GTK_CONTAINER (label_ebox), label_hbox);
|
||||
|
||||
/* setup icon */
|
||||
gtk_box_pack_start (GTK_BOX (label_hbox), icon, FALSE, FALSE, 0);
|
||||
|
||||
/* setup label */
|
||||
label = gtk_label_new (name);
|
||||
#if GTK_CHECK_VERSION (3, 16, 0)
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
|
||||
#endif
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
gtk_widget_set_margin_left (label, 0);
|
||||
gtk_widget_set_margin_right (label, 0);
|
||||
gtk_widget_set_margin_top (label, 0);
|
||||
gtk_widget_set_margin_bottom (label, 0);
|
||||
#else
|
||||
gtk_misc_set_padding (GTK_MISC (label), 0, 0);
|
||||
#endif
|
||||
gtk_box_pack_start (GTK_BOX (label_hbox), label, TRUE, TRUE, 0);
|
||||
|
||||
gtk_widget_set_tooltip_text (label_ebox, name);
|
||||
|
||||
gtk_widget_show_all (hbox);
|
||||
|
||||
if (panel->priv->orientation == GTK_ORIENTATION_VERTICAL)
|
||||
gtk_widget_hide(label);
|
||||
|
||||
g_object_set_data (G_OBJECT (item), "label", label);
|
||||
g_object_set_data (G_OBJECT (item), "hbox", hbox);
|
||||
|
||||
return hbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_panel_add_item:
|
||||
* @panel: a #XedPanel
|
||||
* @item: the #GtkWidget to add to the @panel
|
||||
* @name: the name to be shown in the @panel
|
||||
* @image: the image to be shown in the @panel
|
||||
*
|
||||
* Adds a new item to the @panel.
|
||||
*/
|
||||
void
|
||||
xed_panel_add_item (XedPanel *panel,
|
||||
GtkWidget *item,
|
||||
const gchar *name,
|
||||
GtkWidget *image)
|
||||
{
|
||||
XedPanelItem *data;
|
||||
GtkWidget *tab_label;
|
||||
GtkWidget *menu_label;
|
||||
gint w, h;
|
||||
|
||||
g_return_if_fail (XED_IS_PANEL (panel));
|
||||
g_return_if_fail (GTK_IS_WIDGET (item));
|
||||
g_return_if_fail (name != NULL);
|
||||
g_return_if_fail (image == NULL || GTK_IS_IMAGE (image));
|
||||
|
||||
data = g_new (XedPanelItem, 1);
|
||||
|
||||
data->name = g_strdup (name);
|
||||
|
||||
if (image == NULL)
|
||||
{
|
||||
/* default to empty */
|
||||
data->icon = gtk_image_new_from_stock (GTK_STOCK_FILE,
|
||||
GTK_ICON_SIZE_MENU);
|
||||
}
|
||||
else
|
||||
{
|
||||
data->icon = image;
|
||||
}
|
||||
|
||||
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
|
||||
gtk_widget_set_size_request (data->icon, w, h);
|
||||
|
||||
g_object_set_data (G_OBJECT (item),
|
||||
PANEL_ITEM_KEY,
|
||||
data);
|
||||
|
||||
tab_label = build_tab_label (panel, item, data->name, data->icon);
|
||||
|
||||
menu_label = gtk_label_new (name);
|
||||
#if GTK_CHECK_VERSION (3, 16, 0)
|
||||
gtk_label_set_xalign (GTK_LABEL (menu_label), 0.0);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
|
||||
#endif
|
||||
|
||||
if (!gtk_widget_get_visible (item))
|
||||
gtk_widget_show (item);
|
||||
|
||||
gtk_notebook_append_page_menu (GTK_NOTEBOOK (panel->priv->notebook),
|
||||
item,
|
||||
tab_label,
|
||||
menu_label);
|
||||
|
||||
g_signal_emit (G_OBJECT (panel), signals[ITEM_ADDED], 0, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_panel_add_item_with_stock_icon:
|
||||
* @panel: a #XedPanel
|
||||
* @item: the #GtkWidget to add to the @panel
|
||||
* @name: the name to be shown in the @panel
|
||||
* @stock_id: a stock id
|
||||
*
|
||||
* Same as xed_panel_add_item() but using an image from stock.
|
||||
*/
|
||||
void
|
||||
xed_panel_add_item_with_stock_icon (XedPanel *panel,
|
||||
GtkWidget *item,
|
||||
const gchar *name,
|
||||
const gchar *stock_id)
|
||||
{
|
||||
GtkWidget *icon = NULL;
|
||||
|
||||
if (stock_id != NULL)
|
||||
{
|
||||
icon = gtk_image_new_from_stock (stock_id,
|
||||
GTK_ICON_SIZE_MENU);
|
||||
}
|
||||
|
||||
xed_panel_add_item (panel, item, name, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_panel_remove_item:
|
||||
* @panel: a #XedPanel
|
||||
* @item: the item to be removed from the panel
|
||||
*
|
||||
* Removes the widget @item from the panel if it is in the @panel and returns
|
||||
* %TRUE if there was not any problem.
|
||||
*
|
||||
* Returns: %TRUE if it was well removed.
|
||||
*/
|
||||
gboolean
|
||||
xed_panel_remove_item (XedPanel *panel,
|
||||
GtkWidget *item)
|
||||
{
|
||||
XedPanelItem *data;
|
||||
gint page_num;
|
||||
|
||||
g_return_val_if_fail (XED_IS_PANEL (panel), FALSE);
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (item), FALSE);
|
||||
|
||||
page_num = gtk_notebook_page_num (GTK_NOTEBOOK (panel->priv->notebook),
|
||||
item);
|
||||
|
||||
if (page_num == -1)
|
||||
return FALSE;
|
||||
|
||||
data = (XedPanelItem *)g_object_get_data (G_OBJECT (item),
|
||||
PANEL_ITEM_KEY);
|
||||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
|
||||
g_free (data->name);
|
||||
g_free (data);
|
||||
|
||||
g_object_set_data (G_OBJECT (item),
|
||||
PANEL_ITEM_KEY,
|
||||
NULL);
|
||||
|
||||
/* ref the item to keep it alive during signal emission */
|
||||
g_object_ref (G_OBJECT (item));
|
||||
|
||||
gtk_notebook_remove_page (GTK_NOTEBOOK (panel->priv->notebook),
|
||||
page_num);
|
||||
|
||||
/* if we removed all the pages, reset the title */
|
||||
if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (panel->priv->notebook)) == 0)
|
||||
sync_title (panel, NULL);
|
||||
|
||||
g_signal_emit (G_OBJECT (panel), signals[ITEM_REMOVED], 0, item);
|
||||
|
||||
g_object_unref (G_OBJECT (item));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_panel_activate_item:
|
||||
* @panel: a #XedPanel
|
||||
* @item: the item to be activated
|
||||
*
|
||||
* Switches to the page that contains @item.
|
||||
*
|
||||
* Returns: %TRUE if it was activated
|
||||
*/
|
||||
gboolean
|
||||
xed_panel_activate_item (XedPanel *panel,
|
||||
GtkWidget *item)
|
||||
{
|
||||
gint page_num;
|
||||
|
||||
g_return_val_if_fail (XED_IS_PANEL (panel), FALSE);
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (item), FALSE);
|
||||
|
||||
page_num = gtk_notebook_page_num (GTK_NOTEBOOK (panel->priv->notebook),
|
||||
item);
|
||||
|
||||
if (page_num == -1)
|
||||
return FALSE;
|
||||
|
||||
gtk_notebook_set_current_page (GTK_NOTEBOOK (panel->priv->notebook),
|
||||
page_num);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_panel_item_is_active:
|
||||
* @panel: a #XedPanel
|
||||
* @item: a #GtkWidget
|
||||
*
|
||||
* Returns whether @item is the active widget in @panel
|
||||
*
|
||||
* Returns: %TRUE if @item is the active widget
|
||||
*/
|
||||
gboolean
|
||||
xed_panel_item_is_active (XedPanel *panel,
|
||||
GtkWidget *item)
|
||||
{
|
||||
gint cur_page;
|
||||
gint page_num;
|
||||
|
||||
g_return_val_if_fail (XED_IS_PANEL (panel), FALSE);
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (item), FALSE);
|
||||
|
||||
page_num = gtk_notebook_page_num (GTK_NOTEBOOK (panel->priv->notebook),
|
||||
item);
|
||||
|
||||
if (page_num == -1)
|
||||
return FALSE;
|
||||
|
||||
cur_page = gtk_notebook_get_current_page (
|
||||
GTK_NOTEBOOK (panel->priv->notebook));
|
||||
|
||||
return (page_num == cur_page);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_panel_get_orientation:
|
||||
* @panel: a #XedPanel
|
||||
*
|
||||
* Gets the orientation of the @panel.
|
||||
*
|
||||
* Returns: the #GtkOrientation of #XedPanel
|
||||
*/
|
||||
GtkOrientation
|
||||
xed_panel_get_orientation (XedPanel *panel)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_PANEL (panel), GTK_ORIENTATION_VERTICAL);
|
||||
|
||||
return panel->priv->orientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_panel_get_n_items:
|
||||
* @panel: a #XedPanel
|
||||
*
|
||||
* Gets the number of items in a @panel.
|
||||
*
|
||||
* Returns: the number of items contained in #XedPanel
|
||||
*/
|
||||
gint
|
||||
xed_panel_get_n_items (XedPanel *panel)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_PANEL (panel), -1);
|
||||
|
||||
return gtk_notebook_get_n_pages (GTK_NOTEBOOK (panel->priv->notebook));
|
||||
}
|
||||
|
||||
gint
|
||||
_xed_panel_get_active_item_id (XedPanel *panel)
|
||||
{
|
||||
gint cur_page;
|
||||
GtkWidget *item;
|
||||
XedPanelItem *data;
|
||||
|
||||
g_return_val_if_fail (XED_IS_PANEL (panel), 0);
|
||||
|
||||
cur_page = gtk_notebook_get_current_page (
|
||||
GTK_NOTEBOOK (panel->priv->notebook));
|
||||
if (cur_page == -1)
|
||||
return 0;
|
||||
|
||||
item = gtk_notebook_get_nth_page (
|
||||
GTK_NOTEBOOK (panel->priv->notebook),
|
||||
cur_page);
|
||||
|
||||
/* FIXME: for now we use as the hash of the name as id.
|
||||
* However the name is not guaranteed to be unique and
|
||||
* it is a translated string, so it's subotimal, but should
|
||||
* be good enough for now since we don't want to add an
|
||||
* ad hoc id argument.
|
||||
*/
|
||||
|
||||
data = (XedPanelItem *)g_object_get_data (G_OBJECT (item),
|
||||
PANEL_ITEM_KEY);
|
||||
g_return_val_if_fail (data != NULL, 0);
|
||||
|
||||
return g_str_hash (data->name);
|
||||
}
|
||||
|
||||
void
|
||||
_xed_panel_set_active_item_by_id (XedPanel *panel,
|
||||
gint id)
|
||||
{
|
||||
gint n, i;
|
||||
|
||||
g_return_if_fail (XED_IS_PANEL (panel));
|
||||
|
||||
if (id == 0)
|
||||
return;
|
||||
|
||||
n = gtk_notebook_get_n_pages (
|
||||
GTK_NOTEBOOK (panel->priv->notebook));
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GtkWidget *item;
|
||||
XedPanelItem *data;
|
||||
|
||||
item = gtk_notebook_get_nth_page (
|
||||
GTK_NOTEBOOK (panel->priv->notebook), i);
|
||||
|
||||
data = (XedPanelItem *)g_object_get_data (G_OBJECT (item),
|
||||
PANEL_ITEM_KEY);
|
||||
g_return_if_fail (data != NULL);
|
||||
|
||||
if (g_str_hash (data->name) == id)
|
||||
{
|
||||
gtk_notebook_set_current_page (
|
||||
GTK_NOTEBOOK (panel->priv->notebook), i);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
138
xed/xed-panel.h
Normal file
138
xed/xed-panel.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* xed-panel.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_PANEL_H__
|
||||
#define __XED_PANEL_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_PANEL (xed_panel_get_type())
|
||||
#define XED_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_PANEL, XedPanel))
|
||||
#define XED_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_PANEL, XedPanelClass))
|
||||
#define XED_IS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_PANEL))
|
||||
#define XED_IS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_PANEL))
|
||||
#define XED_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_PANEL, XedPanelClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedPanelPrivate XedPanelPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedPanel XedPanel;
|
||||
|
||||
struct _XedPanel
|
||||
{
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
GtkBox vbox;
|
||||
#else
|
||||
GtkVBox vbox;
|
||||
#endif
|
||||
|
||||
/*< private > */
|
||||
XedPanelPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedPanelClass XedPanelClass;
|
||||
|
||||
struct _XedPanelClass
|
||||
{
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
GtkBoxClass parent_class;
|
||||
#else
|
||||
GtkVBoxClass parent_class;
|
||||
#endif
|
||||
|
||||
void (* item_added) (XedPanel *panel,
|
||||
GtkWidget *item);
|
||||
void (* item_removed) (XedPanel *panel,
|
||||
GtkWidget *item);
|
||||
|
||||
/* Keybinding signals */
|
||||
void (* close) (XedPanel *panel);
|
||||
void (* focus_document) (XedPanel *panel);
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_xed_reserved1) (void);
|
||||
void (*_xed_reserved2) (void);
|
||||
void (*_xed_reserved3) (void);
|
||||
void (*_xed_reserved4) (void);
|
||||
};
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_panel_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget *xed_panel_new (GtkOrientation orientation);
|
||||
|
||||
void xed_panel_add_item (XedPanel *panel,
|
||||
GtkWidget *item,
|
||||
const gchar *name,
|
||||
GtkWidget *image);
|
||||
|
||||
void xed_panel_add_item_with_stock_icon (XedPanel *panel,
|
||||
GtkWidget *item,
|
||||
const gchar *name,
|
||||
const gchar *stock_id);
|
||||
|
||||
gboolean xed_panel_remove_item (XedPanel *panel,
|
||||
GtkWidget *item);
|
||||
|
||||
gboolean xed_panel_activate_item (XedPanel *panel,
|
||||
GtkWidget *item);
|
||||
|
||||
gboolean xed_panel_item_is_active (XedPanel *panel,
|
||||
GtkWidget *item);
|
||||
|
||||
GtkOrientation xed_panel_get_orientation (XedPanel *panel);
|
||||
|
||||
gint xed_panel_get_n_items (XedPanel *panel);
|
||||
|
||||
|
||||
/*
|
||||
* Non exported functions
|
||||
*/
|
||||
gint _xed_panel_get_active_item_id (XedPanel *panel);
|
||||
|
||||
void _xed_panel_set_active_item_by_id (XedPanel *panel,
|
||||
gint id);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_PANEL_H__ */
|
||||
68
xed/xed-plugin-info-priv.h
Normal file
68
xed/xed-plugin-info-priv.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* xed-plugin-info-priv.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 - Paolo Maggi
|
||||
* Copyright (C) 2007 - Paolo Maggi, Steve Frécinaux
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2007. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_PLUGIN_INFO_PRIV_H__
|
||||
#define __XED_PLUGIN_INFO_PRIV_H__
|
||||
|
||||
#include "xed-plugin-info.h"
|
||||
#include "xed-plugin.h"
|
||||
|
||||
struct _XedPluginInfo
|
||||
{
|
||||
gint refcount;
|
||||
|
||||
XedPlugin *plugin;
|
||||
gchar *file;
|
||||
|
||||
gchar *module_name;
|
||||
gchar *loader;
|
||||
gchar **dependencies;
|
||||
|
||||
gchar *name;
|
||||
gchar *desc;
|
||||
gchar *icon_name;
|
||||
gchar **authors;
|
||||
gchar *copyright;
|
||||
gchar *website;
|
||||
gchar *version;
|
||||
|
||||
/* A plugin is unavailable if it is not possible to activate it
|
||||
due to an error loading the plugin module (e.g. for Python plugins
|
||||
when the interpreter has not been correctly initializated) */
|
||||
gint available : 1;
|
||||
};
|
||||
|
||||
XedPluginInfo *_xed_plugin_info_new (const gchar *file);
|
||||
void _xed_plugin_info_ref (XedPluginInfo *info);
|
||||
void _xed_plugin_info_unref (XedPluginInfo *info);
|
||||
|
||||
|
||||
#endif /* __XED_PLUGIN_INFO_PRIV_H__ */
|
||||
396
xed/xed-plugin-info.c
Normal file
396
xed/xed-plugin-info.c
Normal file
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* xed-plugin-info.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 - Paolo Maggi
|
||||
* Copyright (C) 2007 - Paolo Maggi, Steve Frécinaux
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2007. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "xed-plugin-info.h"
|
||||
#include "xed-plugin-info-priv.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-plugin.h"
|
||||
|
||||
void
|
||||
_xed_plugin_info_ref (XedPluginInfo *info)
|
||||
{
|
||||
g_atomic_int_inc (&info->refcount);
|
||||
}
|
||||
|
||||
static XedPluginInfo *
|
||||
xed_plugin_info_copy (XedPluginInfo *info)
|
||||
{
|
||||
_xed_plugin_info_ref (info);
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
_xed_plugin_info_unref (XedPluginInfo *info)
|
||||
{
|
||||
if (!g_atomic_int_dec_and_test (&info->refcount))
|
||||
return;
|
||||
|
||||
if (info->plugin != NULL)
|
||||
{
|
||||
xed_debug_message (DEBUG_PLUGINS, "Unref plugin %s", info->name);
|
||||
|
||||
g_object_unref (info->plugin);
|
||||
}
|
||||
|
||||
g_free (info->file);
|
||||
g_free (info->module_name);
|
||||
g_strfreev (info->dependencies);
|
||||
g_free (info->name);
|
||||
g_free (info->desc);
|
||||
g_free (info->icon_name);
|
||||
g_free (info->website);
|
||||
g_free (info->copyright);
|
||||
g_free (info->loader);
|
||||
g_free (info->version);
|
||||
g_strfreev (info->authors);
|
||||
|
||||
g_free (info);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_plugin_info_get_type:
|
||||
*
|
||||
* Retrieves the #GType object which is associated with the #XedPluginInfo
|
||||
* class.
|
||||
*
|
||||
* Return value: the GType associated with #XedPluginInfo.
|
||||
**/
|
||||
GType
|
||||
xed_plugin_info_get_type (void)
|
||||
{
|
||||
static GType the_type = 0;
|
||||
|
||||
if (G_UNLIKELY (!the_type))
|
||||
the_type = g_boxed_type_register_static (
|
||||
"XedPluginInfo",
|
||||
(GBoxedCopyFunc) xed_plugin_info_copy,
|
||||
(GBoxedFreeFunc) _xed_plugin_info_unref);
|
||||
|
||||
return the_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_plugin_info_new:
|
||||
* @filename: the filename where to read the plugin information
|
||||
*
|
||||
* Creates a new #XedPluginInfo from a file on the disk.
|
||||
*
|
||||
* Return value: a newly created #XedPluginInfo.
|
||||
*/
|
||||
XedPluginInfo *
|
||||
_xed_plugin_info_new (const gchar *file)
|
||||
{
|
||||
XedPluginInfo *info;
|
||||
GKeyFile *plugin_file = NULL;
|
||||
gchar *str;
|
||||
|
||||
g_return_val_if_fail (file != NULL, NULL);
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "Loading plugin: %s", file);
|
||||
|
||||
info = g_new0 (XedPluginInfo, 1);
|
||||
info->refcount = 1;
|
||||
info->file = g_strdup (file);
|
||||
|
||||
plugin_file = g_key_file_new ();
|
||||
if (!g_key_file_load_from_file (plugin_file, file, G_KEY_FILE_NONE, NULL))
|
||||
{
|
||||
g_warning ("Bad plugin file: %s", file);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!g_key_file_has_key (plugin_file,
|
||||
"Xed Plugin",
|
||||
"IAge",
|
||||
NULL))
|
||||
{
|
||||
xed_debug_message (DEBUG_PLUGINS,
|
||||
"IAge key does not exist in file: %s", file);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Check IAge=2 */
|
||||
if (g_key_file_get_integer (plugin_file,
|
||||
"Xed Plugin",
|
||||
"IAge",
|
||||
NULL) != 2)
|
||||
{
|
||||
xed_debug_message (DEBUG_PLUGINS,
|
||||
"Wrong IAge in file: %s", file);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get module name */
|
||||
str = g_key_file_get_string (plugin_file,
|
||||
"Xed Plugin",
|
||||
"Module",
|
||||
NULL);
|
||||
|
||||
if ((str != NULL) && (*str != '\0'))
|
||||
{
|
||||
info->module_name = str;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Could not find 'Module' in %s", file);
|
||||
g_free (str);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get the dependency list */
|
||||
info->dependencies = g_key_file_get_string_list (plugin_file,
|
||||
"Xed Plugin",
|
||||
"Depends",
|
||||
NULL,
|
||||
NULL);
|
||||
if (info->dependencies == NULL)
|
||||
{
|
||||
xed_debug_message (DEBUG_PLUGINS, "Could not find 'Depends' in %s", file);
|
||||
info->dependencies = g_new0 (gchar *, 1);
|
||||
}
|
||||
|
||||
/* Get the loader for this plugin */
|
||||
str = g_key_file_get_string (plugin_file,
|
||||
"Xed Plugin",
|
||||
"Loader",
|
||||
NULL);
|
||||
|
||||
if ((str != NULL) && (*str != '\0'))
|
||||
{
|
||||
info->loader = str;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* default to the C loader */
|
||||
info->loader = g_strdup("c");
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
/* Get Name */
|
||||
str = g_key_file_get_locale_string (plugin_file,
|
||||
"Xed Plugin",
|
||||
"Name",
|
||||
NULL, NULL);
|
||||
if (str)
|
||||
info->name = str;
|
||||
else
|
||||
{
|
||||
g_warning ("Could not find 'Name' in %s", file);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get Description */
|
||||
str = g_key_file_get_locale_string (plugin_file,
|
||||
"Xed Plugin",
|
||||
"Description",
|
||||
NULL, NULL);
|
||||
if (str)
|
||||
info->desc = str;
|
||||
else
|
||||
xed_debug_message (DEBUG_PLUGINS, "Could not find 'Description' in %s", file);
|
||||
|
||||
/* Get Icon */
|
||||
str = g_key_file_get_locale_string (plugin_file,
|
||||
"Xed Plugin",
|
||||
"Icon",
|
||||
NULL, NULL);
|
||||
if (str)
|
||||
info->icon_name = str;
|
||||
else
|
||||
xed_debug_message (DEBUG_PLUGINS, "Could not find 'Icon' in %s, using 'xed-plugin'", file);
|
||||
|
||||
|
||||
/* Get Authors */
|
||||
info->authors = g_key_file_get_string_list (plugin_file,
|
||||
"Xed Plugin",
|
||||
"Authors",
|
||||
NULL,
|
||||
NULL);
|
||||
if (info->authors == NULL)
|
||||
xed_debug_message (DEBUG_PLUGINS, "Could not find 'Authors' in %s", file);
|
||||
|
||||
|
||||
/* Get Copyright */
|
||||
str = g_key_file_get_string (plugin_file,
|
||||
"Xed Plugin",
|
||||
"Copyright",
|
||||
NULL);
|
||||
if (str)
|
||||
info->copyright = str;
|
||||
else
|
||||
xed_debug_message (DEBUG_PLUGINS, "Could not find 'Copyright' in %s", file);
|
||||
|
||||
/* Get Website */
|
||||
str = g_key_file_get_string (plugin_file,
|
||||
"Xed Plugin",
|
||||
"Website",
|
||||
NULL);
|
||||
if (str)
|
||||
info->website = str;
|
||||
else
|
||||
xed_debug_message (DEBUG_PLUGINS, "Could not find 'Website' in %s", file);
|
||||
|
||||
/* Get Version */
|
||||
str = g_key_file_get_string (plugin_file,
|
||||
"Xed Plugin",
|
||||
"Version",
|
||||
NULL);
|
||||
if (str)
|
||||
info->version = str;
|
||||
else
|
||||
xed_debug_message (DEBUG_PLUGINS, "Could not find 'Version' in %s", file);
|
||||
|
||||
g_key_file_free (plugin_file);
|
||||
|
||||
/* If we know nothing about the availability of the plugin,
|
||||
set it as available */
|
||||
info->available = TRUE;
|
||||
|
||||
return info;
|
||||
|
||||
error:
|
||||
g_free (info->file);
|
||||
g_free (info->module_name);
|
||||
g_free (info->name);
|
||||
g_free (info->loader);
|
||||
g_free (info);
|
||||
g_key_file_free (plugin_file);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_plugin_info_is_active (XedPluginInfo *info)
|
||||
{
|
||||
g_return_val_if_fail (info != NULL, FALSE);
|
||||
|
||||
return info->available && info->plugin != NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_plugin_info_is_available (XedPluginInfo *info)
|
||||
{
|
||||
g_return_val_if_fail (info != NULL, FALSE);
|
||||
|
||||
return info->available != FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_plugin_info_is_configurable (XedPluginInfo *info)
|
||||
{
|
||||
xed_debug_message (DEBUG_PLUGINS, "Is '%s' configurable?", info->name);
|
||||
|
||||
g_return_val_if_fail (info != NULL, FALSE);
|
||||
|
||||
if (info->plugin == NULL || !info->available)
|
||||
return FALSE;
|
||||
|
||||
return xed_plugin_is_configurable (info->plugin);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_plugin_info_get_module_name (XedPluginInfo *info)
|
||||
{
|
||||
g_return_val_if_fail (info != NULL, NULL);
|
||||
|
||||
return info->module_name;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_plugin_info_get_name (XedPluginInfo *info)
|
||||
{
|
||||
g_return_val_if_fail (info != NULL, NULL);
|
||||
|
||||
return info->name;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_plugin_info_get_description (XedPluginInfo *info)
|
||||
{
|
||||
g_return_val_if_fail (info != NULL, NULL);
|
||||
|
||||
return info->desc;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_plugin_info_get_icon_name (XedPluginInfo *info)
|
||||
{
|
||||
g_return_val_if_fail (info != NULL, NULL);
|
||||
|
||||
/* use the xed-plugin icon as a default if the plugin does not
|
||||
have its own */
|
||||
if (info->icon_name != NULL &&
|
||||
gtk_icon_theme_has_icon (gtk_icon_theme_get_default (),
|
||||
info->icon_name))
|
||||
return info->icon_name;
|
||||
else
|
||||
return "xed-plugin";
|
||||
}
|
||||
|
||||
const gchar **
|
||||
xed_plugin_info_get_authors (XedPluginInfo *info)
|
||||
{
|
||||
g_return_val_if_fail (info != NULL, (const gchar **)NULL);
|
||||
|
||||
return (const gchar **) info->authors;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_plugin_info_get_website (XedPluginInfo *info)
|
||||
{
|
||||
g_return_val_if_fail (info != NULL, NULL);
|
||||
|
||||
return info->website;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_plugin_info_get_copyright (XedPluginInfo *info)
|
||||
{
|
||||
g_return_val_if_fail (info != NULL, NULL);
|
||||
|
||||
return info->copyright;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_plugin_info_get_version (XedPluginInfo *info)
|
||||
{
|
||||
g_return_val_if_fail (info != NULL, NULL);
|
||||
|
||||
return info->version;
|
||||
}
|
||||
63
xed/xed-plugin-info.h
Normal file
63
xed/xed-plugin-info.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* xed-plugin-info.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 - Paolo Maggi
|
||||
* Copyright (C) 2007 - Paolo Maggi, Steve Frécinaux
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2007. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_PLUGIN_INFO_H__
|
||||
#define __XED_PLUGIN_INFO_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_PLUGIN_INFO (xed_plugin_info_get_type ())
|
||||
#define XED_PLUGIN_INFO(obj) ((XedPluginInfo *) (obj))
|
||||
|
||||
typedef struct _XedPluginInfo XedPluginInfo;
|
||||
|
||||
GType xed_plugin_info_get_type (void) G_GNUC_CONST;
|
||||
|
||||
gboolean xed_plugin_info_is_active (XedPluginInfo *info);
|
||||
gboolean xed_plugin_info_is_available (XedPluginInfo *info);
|
||||
gboolean xed_plugin_info_is_configurable (XedPluginInfo *info);
|
||||
|
||||
const gchar *xed_plugin_info_get_module_name (XedPluginInfo *info);
|
||||
|
||||
const gchar *xed_plugin_info_get_name (XedPluginInfo *info);
|
||||
const gchar *xed_plugin_info_get_description (XedPluginInfo *info);
|
||||
const gchar *xed_plugin_info_get_icon_name (XedPluginInfo *info);
|
||||
const gchar **xed_plugin_info_get_authors (XedPluginInfo *info);
|
||||
const gchar *xed_plugin_info_get_website (XedPluginInfo *info);
|
||||
const gchar *xed_plugin_info_get_copyright (XedPluginInfo *info);
|
||||
const gchar *xed_plugin_info_get_version (XedPluginInfo *info);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_PLUGIN_INFO_H__ */
|
||||
|
||||
131
xed/xed-plugin-loader.c
Normal file
131
xed/xed-plugin-loader.c
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* xed-plugin-loader.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2008 - Jesse van den Kieboom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "xed-plugin-loader.h"
|
||||
|
||||
static void
|
||||
xed_plugin_loader_base_init (gpointer g_class)
|
||||
{
|
||||
static gboolean initialized = FALSE;
|
||||
|
||||
if (G_UNLIKELY (!initialized))
|
||||
{
|
||||
/* create interface signals here. */
|
||||
initialized = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
GType
|
||||
xed_plugin_loader_get_type (void)
|
||||
{
|
||||
static GType type = 0;
|
||||
|
||||
if (G_UNLIKELY (type == 0))
|
||||
{
|
||||
static const GTypeInfo info =
|
||||
{
|
||||
sizeof (XedPluginLoaderInterface),
|
||||
xed_plugin_loader_base_init, /* base_init */
|
||||
NULL, /* base_finalize */
|
||||
NULL, /* class_init */
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
0,
|
||||
0, /* n_preallocs */
|
||||
NULL /* instance_init */
|
||||
};
|
||||
|
||||
type = g_type_register_static (G_TYPE_INTERFACE, "XedPluginLoader", &info, 0);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
xed_plugin_loader_type_get_id (GType type)
|
||||
{
|
||||
GTypeClass *klass;
|
||||
XedPluginLoaderInterface *iface;
|
||||
|
||||
klass = g_type_class_ref (type);
|
||||
|
||||
if (klass == NULL)
|
||||
{
|
||||
g_warning ("Could not get class info for plugin loader");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iface = g_type_interface_peek (klass, XED_TYPE_PLUGIN_LOADER);
|
||||
|
||||
if (iface == NULL)
|
||||
{
|
||||
g_warning ("Could not get plugin loader interface");
|
||||
g_type_class_unref (klass);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_return_val_if_fail (iface->get_id != NULL, NULL);
|
||||
return iface->get_id ();
|
||||
}
|
||||
|
||||
XedPlugin *
|
||||
xed_plugin_loader_load (XedPluginLoader *loader,
|
||||
XedPluginInfo *info,
|
||||
const gchar *path)
|
||||
{
|
||||
XedPluginLoaderInterface *iface;
|
||||
|
||||
g_return_val_if_fail (XED_IS_PLUGIN_LOADER (loader), NULL);
|
||||
|
||||
iface = XED_PLUGIN_LOADER_GET_INTERFACE (loader);
|
||||
g_return_val_if_fail (iface->load != NULL, NULL);
|
||||
|
||||
return iface->load (loader, info, path);
|
||||
}
|
||||
|
||||
void
|
||||
xed_plugin_loader_unload (XedPluginLoader *loader,
|
||||
XedPluginInfo *info)
|
||||
{
|
||||
XedPluginLoaderInterface *iface;
|
||||
|
||||
g_return_if_fail (XED_IS_PLUGIN_LOADER (loader));
|
||||
|
||||
iface = XED_PLUGIN_LOADER_GET_INTERFACE (loader);
|
||||
g_return_if_fail (iface->unload != NULL);
|
||||
|
||||
iface->unload (loader, info);
|
||||
}
|
||||
|
||||
void
|
||||
xed_plugin_loader_garbage_collect (XedPluginLoader *loader)
|
||||
{
|
||||
XedPluginLoaderInterface *iface;
|
||||
|
||||
g_return_if_fail (XED_IS_PLUGIN_LOADER (loader));
|
||||
|
||||
iface = XED_PLUGIN_LOADER_GET_INTERFACE (loader);
|
||||
|
||||
if (iface->garbage_collect != NULL)
|
||||
iface->garbage_collect (loader);
|
||||
}
|
||||
106
xed/xed-plugin-loader.h
Normal file
106
xed/xed-plugin-loader.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* xed-plugin-loader.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2008 - Jesse van den Kieboom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __XED_PLUGIN_LOADER_H__
|
||||
#define __XED_PLUGIN_LOADER_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <xed/xed-plugin.h>
|
||||
#include <xed/xed-plugin-info.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_PLUGIN_LOADER (xed_plugin_loader_get_type ())
|
||||
#define XED_PLUGIN_LOADER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_PLUGIN_LOADER, XedPluginLoader))
|
||||
#define XED_IS_PLUGIN_LOADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_PLUGIN_LOADER))
|
||||
#define XED_PLUGIN_LOADER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), XED_TYPE_PLUGIN_LOADER, XedPluginLoaderInterface))
|
||||
|
||||
typedef struct _XedPluginLoader XedPluginLoader; /* dummy object */
|
||||
typedef struct _XedPluginLoaderInterface XedPluginLoaderInterface;
|
||||
|
||||
struct _XedPluginLoaderInterface {
|
||||
GTypeInterface parent;
|
||||
|
||||
const gchar *(*get_id) (void);
|
||||
|
||||
XedPlugin *(*load) (XedPluginLoader *loader,
|
||||
XedPluginInfo *info,
|
||||
const gchar *path);
|
||||
|
||||
void (*unload) (XedPluginLoader *loader,
|
||||
XedPluginInfo *info);
|
||||
|
||||
void (*garbage_collect) (XedPluginLoader *loader);
|
||||
};
|
||||
|
||||
GType xed_plugin_loader_get_type (void);
|
||||
|
||||
const gchar *xed_plugin_loader_type_get_id (GType type);
|
||||
XedPlugin *xed_plugin_loader_load (XedPluginLoader *loader,
|
||||
XedPluginInfo *info,
|
||||
const gchar *path);
|
||||
void xed_plugin_loader_unload (XedPluginLoader *loader,
|
||||
XedPluginInfo *info);
|
||||
void xed_plugin_loader_garbage_collect (XedPluginLoader *loader);
|
||||
|
||||
/**
|
||||
* XED_PLUGIN_LOADER_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init):
|
||||
*
|
||||
* Utility macro used to register interfaces for gobject types in plugin loaders.
|
||||
*/
|
||||
#define XED_PLUGIN_LOADER_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init) \
|
||||
const GInterfaceInfo g_implement_interface_info = \
|
||||
{ \
|
||||
(GInterfaceInitFunc) iface_init, \
|
||||
NULL, \
|
||||
NULL \
|
||||
}; \
|
||||
\
|
||||
g_type_module_add_interface (type_module, \
|
||||
g_define_type_id, \
|
||||
TYPE_IFACE, \
|
||||
&g_implement_interface_info);
|
||||
|
||||
/**
|
||||
* XED_PLUGIN_LOADER_REGISTER_TYPE(PluginLoaderName, plugin_loader_name, PARENT_TYPE, loader_interface_init):
|
||||
*
|
||||
* Utility macro used to register plugin loaders.
|
||||
*/
|
||||
#define XED_PLUGIN_LOADER_REGISTER_TYPE(PluginLoaderName, plugin_loader_name, PARENT_TYPE, loader_iface_init) \
|
||||
G_DEFINE_DYNAMIC_TYPE_EXTENDED (PluginLoaderName, \
|
||||
plugin_loader_name, \
|
||||
PARENT_TYPE, \
|
||||
0, \
|
||||
XED_PLUGIN_LOADER_IMPLEMENT_INTERFACE(XED_TYPE_PLUGIN_LOADER, loader_iface_init)); \
|
||||
\
|
||||
\
|
||||
G_MODULE_EXPORT GType \
|
||||
register_xed_plugin_loader (GTypeModule *type_module) \
|
||||
{ \
|
||||
plugin_loader_name##_register_type (type_module); \
|
||||
\
|
||||
return plugin_loader_name##_get_type(); \
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_PLUGIN_LOADER_H__ */
|
||||
906
xed/xed-plugin-manager.c
Normal file
906
xed/xed-plugin-manager.c
Normal file
@@ -0,0 +1,906 @@
|
||||
/*
|
||||
* xed-plugin-manager.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002 Paolo Maggi and James Willcox
|
||||
* Copyright (C) 2003-2006 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 1998-2006. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "xed-plugin-manager.h"
|
||||
#include "xed-utils.h"
|
||||
#include "xed-plugins-engine.h"
|
||||
#include "xed-plugin.h"
|
||||
#include "xed-debug.h"
|
||||
|
||||
enum
|
||||
{
|
||||
ACTIVE_COLUMN,
|
||||
AVAILABLE_COLUMN,
|
||||
INFO_COLUMN,
|
||||
N_COLUMNS
|
||||
};
|
||||
|
||||
#define PLUGIN_MANAGER_NAME_TITLE _("Plugin")
|
||||
#define PLUGIN_MANAGER_ACTIVE_TITLE _("Enabled")
|
||||
|
||||
#define XED_PLUGIN_MANAGER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_PLUGIN_MANAGER, XedPluginManagerPrivate))
|
||||
|
||||
struct _XedPluginManagerPrivate
|
||||
{
|
||||
GtkWidget *tree;
|
||||
|
||||
GtkWidget *about_button;
|
||||
GtkWidget *configure_button;
|
||||
|
||||
XedPluginsEngine *engine;
|
||||
|
||||
GtkWidget *about;
|
||||
|
||||
GtkWidget *popup_menu;
|
||||
};
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
G_DEFINE_TYPE(XedPluginManager, xed_plugin_manager, GTK_TYPE_BOX)
|
||||
#else
|
||||
G_DEFINE_TYPE(XedPluginManager, xed_plugin_manager, GTK_TYPE_VBOX)
|
||||
#endif
|
||||
|
||||
static XedPluginInfo *plugin_manager_get_selected_plugin (XedPluginManager *pm);
|
||||
static void plugin_manager_toggle_active (XedPluginManager *pm, GtkTreeIter *iter, GtkTreeModel *model);
|
||||
static void xed_plugin_manager_finalize (GObject *object);
|
||||
|
||||
static void
|
||||
xed_plugin_manager_class_init (XedPluginManagerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = xed_plugin_manager_finalize;
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (XedPluginManagerPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
about_button_cb (GtkWidget *button,
|
||||
XedPluginManager *pm)
|
||||
{
|
||||
XedPluginInfo *info;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
info = plugin_manager_get_selected_plugin (pm);
|
||||
|
||||
g_return_if_fail (info != NULL);
|
||||
|
||||
/* if there is another about dialog already open destroy it */
|
||||
if (pm->priv->about)
|
||||
gtk_widget_destroy (pm->priv->about);
|
||||
|
||||
pm->priv->about = g_object_new (GTK_TYPE_ABOUT_DIALOG,
|
||||
"program-name", xed_plugin_info_get_name (info),
|
||||
"copyright", xed_plugin_info_get_copyright (info),
|
||||
"authors", xed_plugin_info_get_authors (info),
|
||||
"comments", xed_plugin_info_get_description (info),
|
||||
"website", xed_plugin_info_get_website (info),
|
||||
"logo-icon-name", xed_plugin_info_get_icon_name (info),
|
||||
"version", xed_plugin_info_get_version (info),
|
||||
NULL);
|
||||
|
||||
gtk_window_set_destroy_with_parent (GTK_WINDOW (pm->priv->about),
|
||||
TRUE);
|
||||
|
||||
g_signal_connect (pm->priv->about,
|
||||
"response",
|
||||
G_CALLBACK (gtk_widget_destroy),
|
||||
NULL);
|
||||
g_signal_connect (pm->priv->about,
|
||||
"destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed),
|
||||
&pm->priv->about);
|
||||
|
||||
gtk_window_set_transient_for (GTK_WINDOW (pm->priv->about),
|
||||
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(pm))));
|
||||
gtk_widget_show (pm->priv->about);
|
||||
}
|
||||
|
||||
static void
|
||||
configure_button_cb (GtkWidget *button,
|
||||
XedPluginManager *pm)
|
||||
{
|
||||
XedPluginInfo *info;
|
||||
GtkWindow *toplevel;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
info = plugin_manager_get_selected_plugin (pm);
|
||||
|
||||
g_return_if_fail (info != NULL);
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "Configuring: %s\n",
|
||||
xed_plugin_info_get_name (info));
|
||||
|
||||
toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(pm)));
|
||||
|
||||
xed_plugins_engine_configure_plugin (pm->priv->engine,
|
||||
info, toplevel);
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "Done");
|
||||
}
|
||||
|
||||
static void
|
||||
plugin_manager_view_info_cell_cb (GtkTreeViewColumn *tree_column,
|
||||
GtkCellRenderer *cell,
|
||||
GtkTreeModel *tree_model,
|
||||
GtkTreeIter *iter,
|
||||
gpointer data)
|
||||
{
|
||||
XedPluginInfo *info;
|
||||
gchar *text;
|
||||
|
||||
g_return_if_fail (tree_model != NULL);
|
||||
g_return_if_fail (tree_column != NULL);
|
||||
|
||||
gtk_tree_model_get (tree_model, iter, INFO_COLUMN, &info, -1);
|
||||
|
||||
if (info == NULL)
|
||||
return;
|
||||
|
||||
text = g_markup_printf_escaped ("<b>%s</b>\n%s",
|
||||
xed_plugin_info_get_name (info),
|
||||
xed_plugin_info_get_description (info));
|
||||
g_object_set (G_OBJECT (cell),
|
||||
"markup", text,
|
||||
"sensitive", xed_plugin_info_is_available (info),
|
||||
NULL);
|
||||
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
static void
|
||||
plugin_manager_view_icon_cell_cb (GtkTreeViewColumn *tree_column,
|
||||
GtkCellRenderer *cell,
|
||||
GtkTreeModel *tree_model,
|
||||
GtkTreeIter *iter,
|
||||
gpointer data)
|
||||
{
|
||||
XedPluginInfo *info;
|
||||
|
||||
g_return_if_fail (tree_model != NULL);
|
||||
g_return_if_fail (tree_column != NULL);
|
||||
|
||||
gtk_tree_model_get (tree_model, iter, INFO_COLUMN, &info, -1);
|
||||
|
||||
if (info == NULL)
|
||||
return;
|
||||
|
||||
g_object_set (G_OBJECT (cell),
|
||||
"icon-name", xed_plugin_info_get_icon_name (info),
|
||||
"sensitive", xed_plugin_info_is_available (info),
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
active_toggled_cb (GtkCellRendererToggle *cell,
|
||||
gchar *path_str,
|
||||
XedPluginManager *pm)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkTreePath *path;
|
||||
GtkTreeModel *model;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
path = gtk_tree_path_new_from_string (path_str);
|
||||
|
||||
model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
|
||||
g_return_if_fail (model != NULL);
|
||||
|
||||
gtk_tree_model_get_iter (model, &iter, path);
|
||||
|
||||
if (&iter != NULL)
|
||||
plugin_manager_toggle_active (pm, &iter, model);
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
cursor_changed_cb (GtkTreeView *view,
|
||||
gpointer data)
|
||||
{
|
||||
XedPluginManager *pm = data;
|
||||
XedPluginInfo *info;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
info = plugin_manager_get_selected_plugin (pm);
|
||||
|
||||
gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->about_button),
|
||||
info != NULL);
|
||||
gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button),
|
||||
(info != NULL) &&
|
||||
xed_plugin_info_is_configurable (info));
|
||||
}
|
||||
|
||||
static void
|
||||
row_activated_cb (GtkTreeView *tree_view,
|
||||
GtkTreePath *path,
|
||||
GtkTreeViewColumn *column,
|
||||
gpointer data)
|
||||
{
|
||||
XedPluginManager *pm = data;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
|
||||
|
||||
g_return_if_fail (model != NULL);
|
||||
|
||||
gtk_tree_model_get_iter (model, &iter, path);
|
||||
|
||||
g_return_if_fail (&iter != NULL);
|
||||
|
||||
plugin_manager_toggle_active (pm, &iter, model);
|
||||
}
|
||||
|
||||
static void
|
||||
plugin_manager_populate_lists (XedPluginManager *pm)
|
||||
{
|
||||
const GList *plugins;
|
||||
GtkListStore *model;
|
||||
GtkTreeIter iter;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
plugins = xed_plugins_engine_get_plugin_list (pm->priv->engine);
|
||||
|
||||
model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree)));
|
||||
|
||||
while (plugins)
|
||||
{
|
||||
XedPluginInfo *info;
|
||||
info = (XedPluginInfo *)plugins->data;
|
||||
|
||||
gtk_list_store_append (model, &iter);
|
||||
gtk_list_store_set (model, &iter,
|
||||
ACTIVE_COLUMN, xed_plugin_info_is_active (info),
|
||||
AVAILABLE_COLUMN, xed_plugin_info_is_available (info),
|
||||
INFO_COLUMN, info,
|
||||
-1);
|
||||
|
||||
plugins = plugins->next;
|
||||
}
|
||||
|
||||
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter))
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
XedPluginInfo* info;
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
|
||||
g_return_if_fail (selection != NULL);
|
||||
|
||||
gtk_tree_selection_select_iter (selection, &iter);
|
||||
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
|
||||
INFO_COLUMN, &info, -1);
|
||||
|
||||
gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button),
|
||||
xed_plugin_info_is_configurable (info));
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_manager_set_active (XedPluginManager *pm,
|
||||
GtkTreeIter *iter,
|
||||
GtkTreeModel *model,
|
||||
gboolean active)
|
||||
{
|
||||
XedPluginInfo *info;
|
||||
gboolean res = TRUE;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
|
||||
|
||||
g_return_val_if_fail (info != NULL, FALSE);
|
||||
|
||||
if (active)
|
||||
{
|
||||
/* activate the plugin */
|
||||
if (!xed_plugins_engine_activate_plugin (pm->priv->engine, info)) {
|
||||
xed_debug_message (DEBUG_PLUGINS, "Could not activate %s.\n",
|
||||
xed_plugin_info_get_name (info));
|
||||
|
||||
res = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* deactivate the plugin */
|
||||
if (!xed_plugins_engine_deactivate_plugin (pm->priv->engine, info)) {
|
||||
xed_debug_message (DEBUG_PLUGINS, "Could not deactivate %s.\n",
|
||||
xed_plugin_info_get_name (info));
|
||||
|
||||
res = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
plugin_manager_toggle_active (XedPluginManager *pm,
|
||||
GtkTreeIter *iter,
|
||||
GtkTreeModel *model)
|
||||
{
|
||||
gboolean active;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
gtk_tree_model_get (model, iter, ACTIVE_COLUMN, &active, -1);
|
||||
|
||||
active ^= 1;
|
||||
|
||||
plugin_manager_set_active (pm, iter, model, active);
|
||||
}
|
||||
|
||||
static XedPluginInfo *
|
||||
plugin_manager_get_selected_plugin (XedPluginManager *pm)
|
||||
{
|
||||
XedPluginInfo *info = NULL;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
|
||||
g_return_val_if_fail (model != NULL, NULL);
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
|
||||
g_return_val_if_fail (selection != NULL, NULL);
|
||||
|
||||
if (gtk_tree_selection_get_selected (selection, NULL, &iter))
|
||||
{
|
||||
gtk_tree_model_get (model, &iter, INFO_COLUMN, &info, -1);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void
|
||||
plugin_manager_set_active_all (XedPluginManager *pm,
|
||||
gboolean active)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
|
||||
|
||||
g_return_if_fail (model != NULL);
|
||||
|
||||
gtk_tree_model_get_iter_first (model, &iter);
|
||||
|
||||
do {
|
||||
plugin_manager_set_active (pm, &iter, model, active);
|
||||
}
|
||||
while (gtk_tree_model_iter_next (model, &iter));
|
||||
}
|
||||
|
||||
/* Callback used as the interactive search comparison function */
|
||||
static gboolean
|
||||
name_search_cb (GtkTreeModel *model,
|
||||
gint column,
|
||||
const gchar *key,
|
||||
GtkTreeIter *iter,
|
||||
gpointer data)
|
||||
{
|
||||
XedPluginInfo *info;
|
||||
gchar *normalized_string;
|
||||
gchar *normalized_key;
|
||||
gchar *case_normalized_string;
|
||||
gchar *case_normalized_key;
|
||||
gint key_len;
|
||||
gboolean retval;
|
||||
|
||||
gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
|
||||
if (!info)
|
||||
return FALSE;
|
||||
|
||||
normalized_string = g_utf8_normalize (xed_plugin_info_get_name (info), -1, G_NORMALIZE_ALL);
|
||||
normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
|
||||
case_normalized_string = g_utf8_casefold (normalized_string, -1);
|
||||
case_normalized_key = g_utf8_casefold (normalized_key, -1);
|
||||
|
||||
key_len = strlen (case_normalized_key);
|
||||
|
||||
/* Oddly enough, this callback must return whether to stop the search
|
||||
* because we found a match, not whether we actually matched.
|
||||
*/
|
||||
retval = (strncmp (case_normalized_key, case_normalized_string, key_len) != 0);
|
||||
|
||||
g_free (normalized_key);
|
||||
g_free (normalized_string);
|
||||
g_free (case_normalized_key);
|
||||
g_free (case_normalized_string);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
enable_plugin_menu_cb (GtkMenu *menu,
|
||||
XedPluginManager *pm)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
|
||||
g_return_if_fail (model != NULL);
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
|
||||
g_return_if_fail (selection != NULL);
|
||||
|
||||
if (gtk_tree_selection_get_selected (selection, NULL, &iter))
|
||||
plugin_manager_toggle_active (pm, &iter, model);
|
||||
}
|
||||
|
||||
static void
|
||||
enable_all_menu_cb (GtkMenu *menu,
|
||||
XedPluginManager *pm)
|
||||
{
|
||||
plugin_manager_set_active_all (pm, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
disable_all_menu_cb (GtkMenu *menu,
|
||||
XedPluginManager *pm)
|
||||
{
|
||||
plugin_manager_set_active_all (pm, FALSE);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_tree_popup_menu (XedPluginManager *pm)
|
||||
{
|
||||
GtkWidget *menu;
|
||||
GtkWidget *item;
|
||||
GtkWidget *image;
|
||||
XedPluginInfo *info;
|
||||
|
||||
info = plugin_manager_get_selected_plugin (pm);
|
||||
|
||||
menu = gtk_menu_new ();
|
||||
|
||||
item = gtk_image_menu_item_new_with_mnemonic (_("_About"));
|
||||
image = gtk_image_new_from_stock (GTK_STOCK_ABOUT,
|
||||
GTK_ICON_SIZE_MENU);
|
||||
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
|
||||
g_signal_connect (item, "activate",
|
||||
G_CALLBACK (about_button_cb), pm);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
item = gtk_image_menu_item_new_with_mnemonic (_("C_onfigure"));
|
||||
image = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES,
|
||||
GTK_ICON_SIZE_MENU);
|
||||
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
|
||||
g_signal_connect (item, "activate",
|
||||
G_CALLBACK (configure_button_cb), pm);
|
||||
gtk_widget_set_sensitive (item, xed_plugin_info_is_configurable (info));
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
item = gtk_check_menu_item_new_with_mnemonic (_("A_ctivate"));
|
||||
gtk_widget_set_sensitive (item, xed_plugin_info_is_available (info));
|
||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
|
||||
xed_plugin_info_is_active (info));
|
||||
g_signal_connect (item, "toggled",
|
||||
G_CALLBACK (enable_plugin_menu_cb), pm);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
item = gtk_separator_menu_item_new ();
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
item = gtk_menu_item_new_with_mnemonic (_("Ac_tivate All"));
|
||||
g_signal_connect (item, "activate",
|
||||
G_CALLBACK (enable_all_menu_cb), pm);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
item = gtk_menu_item_new_with_mnemonic (_("_Deactivate All"));
|
||||
g_signal_connect (item, "activate",
|
||||
G_CALLBACK (disable_all_menu_cb), pm);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
gtk_widget_show_all (menu);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
static void
|
||||
tree_popup_menu_detach (XedPluginManager *pm,
|
||||
GtkMenu *menu)
|
||||
{
|
||||
pm->priv->popup_menu = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
show_tree_popup_menu (GtkTreeView *tree,
|
||||
XedPluginManager *pm,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
if (pm->priv->popup_menu)
|
||||
gtk_widget_destroy (pm->priv->popup_menu);
|
||||
|
||||
pm->priv->popup_menu = create_tree_popup_menu (pm);
|
||||
|
||||
gtk_menu_attach_to_widget (GTK_MENU (pm->priv->popup_menu),
|
||||
GTK_WIDGET (pm),
|
||||
(GtkMenuDetachFunc) tree_popup_menu_detach);
|
||||
|
||||
if (event != NULL)
|
||||
{
|
||||
gtk_menu_popup (GTK_MENU (pm->priv->popup_menu), NULL, NULL,
|
||||
NULL, NULL,
|
||||
event->button, event->time);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_menu_popup (GTK_MENU (pm->priv->popup_menu), NULL, NULL,
|
||||
xed_utils_menu_position_under_tree_view, tree,
|
||||
0, gtk_get_current_event_time ());
|
||||
|
||||
gtk_menu_shell_select_first (GTK_MENU_SHELL (pm->priv->popup_menu),
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
button_press_event_cb (GtkWidget *tree,
|
||||
GdkEventButton *event,
|
||||
XedPluginManager *pm)
|
||||
{
|
||||
/* We want the treeview selection to be updated before showing the menu.
|
||||
* This code is evil, thanks to Federico Mena Quintero's black magic.
|
||||
* See: http://mail.gnome.org/archives/gtk-devel-list/2006-February/msg00168.html
|
||||
* FIXME: Let's remove it asap.
|
||||
*/
|
||||
|
||||
static gboolean in_press = FALSE;
|
||||
gboolean handled;
|
||||
|
||||
if (in_press)
|
||||
return FALSE; /* we re-entered */
|
||||
|
||||
if (GDK_BUTTON_PRESS != event->type || 3 != event->button)
|
||||
return FALSE; /* let the normal handler run */
|
||||
|
||||
in_press = TRUE;
|
||||
handled = gtk_widget_event (tree, (GdkEvent *) event);
|
||||
in_press = FALSE;
|
||||
|
||||
if (!handled)
|
||||
return FALSE;
|
||||
|
||||
/* The selection is fully updated by now */
|
||||
show_tree_popup_menu (GTK_TREE_VIEW (tree), pm, event);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
popup_menu_cb (GtkTreeView *tree,
|
||||
XedPluginManager *pm)
|
||||
{
|
||||
show_tree_popup_menu (tree, pm, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
model_name_sort_func (GtkTreeModel *model,
|
||||
GtkTreeIter *iter1,
|
||||
GtkTreeIter *iter2,
|
||||
gpointer user_data)
|
||||
{
|
||||
XedPluginInfo *info1, *info2;
|
||||
|
||||
gtk_tree_model_get (model, iter1, INFO_COLUMN, &info1, -1);
|
||||
gtk_tree_model_get (model, iter2, INFO_COLUMN, &info2, -1);
|
||||
|
||||
return g_utf8_collate (xed_plugin_info_get_name (info1),
|
||||
xed_plugin_info_get_name (info2));
|
||||
}
|
||||
|
||||
static void
|
||||
plugin_manager_construct_tree (XedPluginManager *pm)
|
||||
{
|
||||
GtkTreeViewColumn *column;
|
||||
GtkCellRenderer *cell;
|
||||
GtkListStore *model;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
model = gtk_list_store_new (N_COLUMNS,
|
||||
G_TYPE_BOOLEAN,
|
||||
G_TYPE_BOOLEAN,
|
||||
G_TYPE_POINTER);
|
||||
|
||||
gtk_tree_view_set_model (GTK_TREE_VIEW (pm->priv->tree),
|
||||
GTK_TREE_MODEL (model));
|
||||
g_object_unref (model);
|
||||
|
||||
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (pm->priv->tree), TRUE);
|
||||
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (pm->priv->tree), FALSE);
|
||||
|
||||
/* first column */
|
||||
cell = gtk_cell_renderer_toggle_new ();
|
||||
g_object_set (cell, "xpad", 6, NULL);
|
||||
g_signal_connect (cell,
|
||||
"toggled",
|
||||
G_CALLBACK (active_toggled_cb),
|
||||
pm);
|
||||
column = gtk_tree_view_column_new_with_attributes (PLUGIN_MANAGER_ACTIVE_TITLE,
|
||||
cell,
|
||||
"active",
|
||||
ACTIVE_COLUMN,
|
||||
"activatable",
|
||||
AVAILABLE_COLUMN,
|
||||
"sensitive",
|
||||
AVAILABLE_COLUMN,
|
||||
NULL);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
|
||||
|
||||
/* second column */
|
||||
column = gtk_tree_view_column_new ();
|
||||
gtk_tree_view_column_set_title (column, PLUGIN_MANAGER_NAME_TITLE);
|
||||
gtk_tree_view_column_set_resizable (column, TRUE);
|
||||
|
||||
cell = gtk_cell_renderer_pixbuf_new ();
|
||||
gtk_tree_view_column_pack_start (column, cell, FALSE);
|
||||
g_object_set (cell, "stock-size", GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
|
||||
gtk_tree_view_column_set_cell_data_func (column, cell,
|
||||
plugin_manager_view_icon_cell_cb,
|
||||
pm, NULL);
|
||||
|
||||
cell = gtk_cell_renderer_text_new ();
|
||||
gtk_tree_view_column_pack_start (column, cell, TRUE);
|
||||
g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
||||
gtk_tree_view_column_set_cell_data_func (column, cell,
|
||||
plugin_manager_view_info_cell_cb,
|
||||
pm, NULL);
|
||||
|
||||
|
||||
gtk_tree_view_column_set_spacing (column, 6);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
|
||||
|
||||
/* Sort on the plugin names */
|
||||
gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model),
|
||||
model_name_sort_func,
|
||||
NULL,
|
||||
NULL);
|
||||
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
|
||||
GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
|
||||
GTK_SORT_ASCENDING);
|
||||
|
||||
/* Enable search for our non-string column */
|
||||
gtk_tree_view_set_search_column (GTK_TREE_VIEW (pm->priv->tree),
|
||||
INFO_COLUMN);
|
||||
gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (pm->priv->tree),
|
||||
name_search_cb,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
g_signal_connect (pm->priv->tree,
|
||||
"cursor_changed",
|
||||
G_CALLBACK (cursor_changed_cb),
|
||||
pm);
|
||||
g_signal_connect (pm->priv->tree,
|
||||
"row_activated",
|
||||
G_CALLBACK (row_activated_cb),
|
||||
pm);
|
||||
|
||||
g_signal_connect (pm->priv->tree,
|
||||
"button-press-event",
|
||||
G_CALLBACK (button_press_event_cb),
|
||||
pm);
|
||||
g_signal_connect (pm->priv->tree,
|
||||
"popup-menu",
|
||||
G_CALLBACK (popup_menu_cb),
|
||||
pm);
|
||||
gtk_widget_show (pm->priv->tree);
|
||||
}
|
||||
|
||||
static void
|
||||
plugin_toggled_cb (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info,
|
||||
XedPluginManager *pm)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
gboolean info_found = FALSE;
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
|
||||
|
||||
if (gtk_tree_selection_get_selected (selection, &model, &iter))
|
||||
{
|
||||
/* There is an item selected: it's probably the one we want! */
|
||||
XedPluginInfo *tinfo;
|
||||
gtk_tree_model_get (model, &iter, INFO_COLUMN, &tinfo, -1);
|
||||
info_found = info == tinfo;
|
||||
}
|
||||
|
||||
if (!info_found)
|
||||
{
|
||||
gtk_tree_model_get_iter_first (model, &iter);
|
||||
|
||||
do
|
||||
{
|
||||
XedPluginInfo *tinfo;
|
||||
gtk_tree_model_get (model, &iter, INFO_COLUMN, &tinfo, -1);
|
||||
info_found = info == tinfo;
|
||||
}
|
||||
while (!info_found && gtk_tree_model_iter_next (model, &iter));
|
||||
}
|
||||
|
||||
if (!info_found)
|
||||
{
|
||||
g_warning ("XedPluginManager: plugin '%s' not found in the tree model",
|
||||
xed_plugin_info_get_name (info));
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_list_store_set (GTK_LIST_STORE (model), &iter, ACTIVE_COLUMN, xed_plugin_info_is_active (info), -1);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugin_manager_init (XedPluginManager *pm)
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkWidget *viewport;
|
||||
GtkWidget *hbuttonbox;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
pm->priv = XED_PLUGIN_MANAGER_GET_PRIVATE (pm);
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (pm),
|
||||
GTK_ORIENTATION_VERTICAL);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Always we create the manager, firstly we rescan the plugins directory
|
||||
*/
|
||||
xed_plugins_engine_rescan_plugins (xed_plugins_engine_get_default ());
|
||||
|
||||
gtk_box_set_spacing (GTK_BOX (pm), 6);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("Active _Plugins:"));
|
||||
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
|
||||
#if GTK_CHECK_VERSION (3, 16, 0)
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
#else
|
||||
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
|
||||
#endif
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (pm), label, FALSE, TRUE, 0);
|
||||
|
||||
viewport = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (viewport),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (viewport),
|
||||
GTK_SHADOW_IN);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (pm), viewport, TRUE, TRUE, 0);
|
||||
|
||||
pm->priv->tree = gtk_tree_view_new ();
|
||||
gtk_container_add (GTK_CONTAINER (viewport), pm->priv->tree);
|
||||
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), pm->priv->tree);
|
||||
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
hbuttonbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
|
||||
#else
|
||||
hbuttonbox = gtk_hbutton_box_new ();
|
||||
#endif
|
||||
gtk_box_pack_start (GTK_BOX (pm), hbuttonbox, FALSE, FALSE, 0);
|
||||
gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END);
|
||||
gtk_box_set_spacing (GTK_BOX (hbuttonbox), 8);
|
||||
|
||||
pm->priv->about_button = xed_gtk_button_new_with_stock_icon (_("_About Plugin"),
|
||||
GTK_STOCK_ABOUT);
|
||||
gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->about_button);
|
||||
|
||||
pm->priv->configure_button = xed_gtk_button_new_with_stock_icon (_("C_onfigure Plugin"),
|
||||
GTK_STOCK_PREFERENCES);
|
||||
gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->configure_button);
|
||||
|
||||
/* setup a window of a sane size. */
|
||||
gtk_widget_set_size_request (GTK_WIDGET (viewport), 270, 100);
|
||||
|
||||
g_signal_connect (pm->priv->about_button,
|
||||
"clicked",
|
||||
G_CALLBACK (about_button_cb),
|
||||
pm);
|
||||
g_signal_connect (pm->priv->configure_button,
|
||||
"clicked",
|
||||
G_CALLBACK (configure_button_cb),
|
||||
pm);
|
||||
|
||||
plugin_manager_construct_tree (pm);
|
||||
|
||||
/* get the plugin engine and populate the treeview */
|
||||
pm->priv->engine = xed_plugins_engine_get_default ();
|
||||
|
||||
g_signal_connect_after (pm->priv->engine,
|
||||
"activate-plugin",
|
||||
G_CALLBACK (plugin_toggled_cb),
|
||||
pm);
|
||||
g_signal_connect_after (pm->priv->engine,
|
||||
"deactivate-plugin",
|
||||
G_CALLBACK (plugin_toggled_cb),
|
||||
pm);
|
||||
|
||||
if (xed_plugins_engine_get_plugin_list (pm->priv->engine) != NULL)
|
||||
{
|
||||
plugin_manager_populate_lists (pm);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_set_sensitive (pm->priv->about_button, FALSE);
|
||||
gtk_widget_set_sensitive (pm->priv->configure_button, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugin_manager_finalize (GObject *object)
|
||||
{
|
||||
XedPluginManager *pm = XED_PLUGIN_MANAGER (object);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (pm->priv->engine,
|
||||
plugin_toggled_cb,
|
||||
pm);
|
||||
|
||||
if (pm->priv->popup_menu)
|
||||
gtk_widget_destroy (pm->priv->popup_menu);
|
||||
|
||||
G_OBJECT_CLASS (xed_plugin_manager_parent_class)->finalize (object);
|
||||
|
||||
}
|
||||
|
||||
GtkWidget *xed_plugin_manager_new (void)
|
||||
{
|
||||
return g_object_new (XED_TYPE_PLUGIN_MANAGER,0);
|
||||
}
|
||||
91
xed/xed-plugin-manager.h
Normal file
91
xed/xed-plugin-manager.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* xed-plugin-manager.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_PLUGIN_MANAGER_H__
|
||||
#define __XED_PLUGIN_MANAGER_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_PLUGIN_MANAGER (xed_plugin_manager_get_type())
|
||||
#define XED_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_PLUGIN_MANAGER, XedPluginManager))
|
||||
#define XED_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_PLUGIN_MANAGER, XedPluginManagerClass))
|
||||
#define XED_IS_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_PLUGIN_MANAGER))
|
||||
#define XED_IS_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_PLUGIN_MANAGER))
|
||||
#define XED_PLUGIN_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_PLUGIN_MANAGER, XedPluginManagerClass))
|
||||
|
||||
/* Private structure type */
|
||||
typedef struct _XedPluginManagerPrivate XedPluginManagerPrivate;
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedPluginManager XedPluginManager;
|
||||
|
||||
struct _XedPluginManager
|
||||
{
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
GtkBox vbox;
|
||||
#else
|
||||
GtkVBox vbox;
|
||||
#endif
|
||||
|
||||
/*< private > */
|
||||
XedPluginManagerPrivate *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedPluginManagerClass XedPluginManagerClass;
|
||||
|
||||
struct _XedPluginManagerClass
|
||||
{
|
||||
#if GTK_CHECK_VERSION (3, 0, 0)
|
||||
GtkBoxClass parent_class;
|
||||
#else
|
||||
GtkVBoxClass parent_class;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_plugin_manager_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget *xed_plugin_manager_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_PLUGIN_MANAGER_H__ */
|
||||
334
xed/xed-plugin.c
Normal file
334
xed/xed-plugin.c
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* xed-plugin.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "xed-plugin.h"
|
||||
#include "xed-dirs.h"
|
||||
|
||||
/* properties */
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_INSTALL_DIR,
|
||||
PROP_DATA_DIR_NAME,
|
||||
PROP_DATA_DIR
|
||||
};
|
||||
|
||||
typedef struct _XedPluginPrivate XedPluginPrivate;
|
||||
|
||||
struct _XedPluginPrivate
|
||||
{
|
||||
gchar *install_dir;
|
||||
gchar *data_dir_name;
|
||||
};
|
||||
|
||||
#define XED_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_PLUGIN, XedPluginPrivate))
|
||||
|
||||
G_DEFINE_TYPE(XedPlugin, xed_plugin, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
dummy (XedPlugin *plugin, XedWindow *window)
|
||||
{
|
||||
/* Empty */
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_configure_dialog (XedPlugin *plugin)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_configurable (XedPlugin *plugin)
|
||||
{
|
||||
return (XED_PLUGIN_GET_CLASS (plugin)->create_configure_dialog !=
|
||||
create_configure_dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugin_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_INSTALL_DIR:
|
||||
g_value_take_string (value, xed_plugin_get_install_dir (XED_PLUGIN (object)));
|
||||
break;
|
||||
case PROP_DATA_DIR:
|
||||
g_value_take_string (value, xed_plugin_get_data_dir (XED_PLUGIN (object)));
|
||||
break;
|
||||
default:
|
||||
g_return_if_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugin_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
XedPluginPrivate *priv = XED_PLUGIN_GET_PRIVATE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_INSTALL_DIR:
|
||||
priv->install_dir = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_DATA_DIR_NAME:
|
||||
priv->data_dir_name = g_value_dup_string (value);
|
||||
break;
|
||||
default:
|
||||
g_return_if_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugin_finalize (GObject *object)
|
||||
{
|
||||
XedPluginPrivate *priv = XED_PLUGIN_GET_PRIVATE (object);
|
||||
|
||||
g_free (priv->install_dir);
|
||||
g_free (priv->data_dir_name);
|
||||
|
||||
G_OBJECT_CLASS (xed_plugin_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugin_class_init (XedPluginClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
klass->activate = dummy;
|
||||
klass->deactivate = dummy;
|
||||
klass->update_ui = dummy;
|
||||
|
||||
klass->create_configure_dialog = create_configure_dialog;
|
||||
klass->is_configurable = is_configurable;
|
||||
|
||||
object_class->get_property = xed_plugin_get_property;
|
||||
object_class->set_property = xed_plugin_set_property;
|
||||
object_class->finalize = xed_plugin_finalize;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_INSTALL_DIR,
|
||||
g_param_spec_string ("install-dir",
|
||||
"Install Directory",
|
||||
"The directory where the plugin is installed",
|
||||
NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
/* the basename of the data dir is set at construction time by the plugin loader
|
||||
* while the full path is constructed on the fly to take into account relocability
|
||||
* that's why we have a writeonly prop and a readonly prop */
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_DATA_DIR_NAME,
|
||||
g_param_spec_string ("data-dir-name",
|
||||
"Basename of the data directory",
|
||||
"The basename of the directory where the plugin should look for its data files",
|
||||
NULL,
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_DATA_DIR,
|
||||
g_param_spec_string ("data-dir",
|
||||
"Data Directory",
|
||||
"The full path of the directory where the plugin should look for its data files",
|
||||
NULL,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_type_class_add_private (klass, sizeof (XedPluginPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugin_init (XedPlugin *plugin)
|
||||
{
|
||||
/* Empty */
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_plugin_get_install_dir:
|
||||
* @plugin: a #XedPlugin
|
||||
*
|
||||
* Get the path of the directory where the plugin is installed.
|
||||
*
|
||||
* Return value: a newly allocated string with the path of the
|
||||
* directory where the plugin is installed
|
||||
*/
|
||||
gchar *
|
||||
xed_plugin_get_install_dir (XedPlugin *plugin)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_PLUGIN (plugin), NULL);
|
||||
|
||||
return g_strdup (XED_PLUGIN_GET_PRIVATE (plugin)->install_dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_plugin_get_data_dir:
|
||||
* @plugin: a #XedPlugin
|
||||
*
|
||||
* Get the path of the directory where the plugin should look for
|
||||
* its data files.
|
||||
*
|
||||
* Return value: a newly allocated string with the path of the
|
||||
* directory where the plugin should look for its data files
|
||||
*/
|
||||
gchar *
|
||||
xed_plugin_get_data_dir (XedPlugin *plugin)
|
||||
{
|
||||
XedPluginPrivate *priv;
|
||||
gchar *xed_lib_dir;
|
||||
gchar *data_dir;
|
||||
|
||||
g_return_val_if_fail (XED_IS_PLUGIN (plugin), NULL);
|
||||
|
||||
priv = XED_PLUGIN_GET_PRIVATE (plugin);
|
||||
|
||||
/* If it's a "user" plugin the data dir is
|
||||
* install_dir/data_dir_name if instead it's a
|
||||
* "system" plugin the data dir is under xed_data_dir,
|
||||
* so it's under $prefix/share/xed/plugins/data_dir_name
|
||||
* where data_dir_name usually it's the name of the plugin
|
||||
*/
|
||||
xed_lib_dir = xed_dirs_get_xed_lib_dir ();
|
||||
|
||||
/* CHECK: is checking the prefix enough or should we be more
|
||||
* careful about normalizing paths etc? */
|
||||
if (g_str_has_prefix (priv->install_dir, xed_lib_dir))
|
||||
{
|
||||
gchar *xed_data_dir;
|
||||
|
||||
xed_data_dir = xed_dirs_get_xed_data_dir ();
|
||||
|
||||
data_dir = g_build_filename (xed_data_dir,
|
||||
"plugins",
|
||||
priv->data_dir_name,
|
||||
NULL);
|
||||
|
||||
g_free (xed_data_dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
data_dir = g_build_filename (priv->install_dir,
|
||||
priv->data_dir_name,
|
||||
NULL);
|
||||
}
|
||||
|
||||
g_free (xed_lib_dir);
|
||||
|
||||
return data_dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_plugin_activate:
|
||||
* @plugin: a #XedPlugin
|
||||
* @window: a #XedWindow
|
||||
*
|
||||
* Activates the plugin.
|
||||
*/
|
||||
void
|
||||
xed_plugin_activate (XedPlugin *plugin,
|
||||
XedWindow *window)
|
||||
{
|
||||
g_return_if_fail (XED_IS_PLUGIN (plugin));
|
||||
g_return_if_fail (XED_IS_WINDOW (window));
|
||||
|
||||
XED_PLUGIN_GET_CLASS (plugin)->activate (plugin, window);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_plugin_deactivate:
|
||||
* @plugin: a #XedPlugin
|
||||
* @window: a #XedWindow
|
||||
*
|
||||
* Deactivates the plugin.
|
||||
*/
|
||||
void
|
||||
xed_plugin_deactivate (XedPlugin *plugin,
|
||||
XedWindow *window)
|
||||
{
|
||||
g_return_if_fail (XED_IS_PLUGIN (plugin));
|
||||
g_return_if_fail (XED_IS_WINDOW (window));
|
||||
|
||||
XED_PLUGIN_GET_CLASS (plugin)->deactivate (plugin, window);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_plugin_update_ui:
|
||||
* @plugin: a #XedPlugin
|
||||
* @window: a #XedWindow
|
||||
*
|
||||
* Triggers an update of the user interface to take into account state changes
|
||||
* caused by the plugin.
|
||||
*/
|
||||
void
|
||||
xed_plugin_update_ui (XedPlugin *plugin,
|
||||
XedWindow *window)
|
||||
{
|
||||
g_return_if_fail (XED_IS_PLUGIN (plugin));
|
||||
g_return_if_fail (XED_IS_WINDOW (window));
|
||||
|
||||
XED_PLUGIN_GET_CLASS (plugin)->update_ui (plugin, window);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_plugin_is_configurable:
|
||||
* @plugin: a #XedPlugin
|
||||
*
|
||||
* Whether the plugin is configurable.
|
||||
*
|
||||
* Returns: TRUE if the plugin is configurable:
|
||||
*/
|
||||
gboolean
|
||||
xed_plugin_is_configurable (XedPlugin *plugin)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_PLUGIN (plugin), FALSE);
|
||||
|
||||
return XED_PLUGIN_GET_CLASS (plugin)->is_configurable (plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* xed_plugin_create_configure_dialog:
|
||||
* @plugin: a #XedPlugin
|
||||
*
|
||||
* Creates the configure dialog widget for the plugin.
|
||||
*
|
||||
* Returns: the configure dialog widget for the plugin.
|
||||
*/
|
||||
GtkWidget *
|
||||
xed_plugin_create_configure_dialog (XedPlugin *plugin)
|
||||
{
|
||||
g_return_val_if_fail (XED_IS_PLUGIN (plugin), NULL);
|
||||
|
||||
return XED_PLUGIN_GET_CLASS (plugin)->create_configure_dialog (plugin);
|
||||
}
|
||||
240
xed/xed-plugin.h
Normal file
240
xed/xed-plugin.h
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* xed-plugin.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_PLUGIN_H__
|
||||
#define __XED_PLUGIN_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <xed/xed-window.h>
|
||||
#include <xed/xed-debug.h>
|
||||
|
||||
/* TODO: add a .h file that includes all the .h files normally needed to
|
||||
* develop a plugin */
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Type checking and casting macros
|
||||
*/
|
||||
#define XED_TYPE_PLUGIN (xed_plugin_get_type())
|
||||
#define XED_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_PLUGIN, XedPlugin))
|
||||
#define XED_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_PLUGIN, XedPluginClass))
|
||||
#define XED_IS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_PLUGIN))
|
||||
#define XED_IS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_PLUGIN))
|
||||
#define XED_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_PLUGIN, XedPluginClass))
|
||||
|
||||
/*
|
||||
* Main object structure
|
||||
*/
|
||||
typedef struct _XedPlugin XedPlugin;
|
||||
|
||||
struct _XedPlugin
|
||||
{
|
||||
GObject parent;
|
||||
};
|
||||
|
||||
/*
|
||||
* Class definition
|
||||
*/
|
||||
typedef struct _XedPluginClass XedPluginClass;
|
||||
|
||||
struct _XedPluginClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Virtual public methods */
|
||||
|
||||
void (*activate) (XedPlugin *plugin,
|
||||
XedWindow *window);
|
||||
void (*deactivate) (XedPlugin *plugin,
|
||||
XedWindow *window);
|
||||
|
||||
void (*update_ui) (XedPlugin *plugin,
|
||||
XedWindow *window);
|
||||
|
||||
GtkWidget *(*create_configure_dialog)
|
||||
(XedPlugin *plugin);
|
||||
|
||||
/* Plugins should not override this, it's handled automatically by
|
||||
the XedPluginClass */
|
||||
gboolean (*is_configurable)
|
||||
(XedPlugin *plugin);
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_xed_reserved1) (void);
|
||||
void (*_xed_reserved2) (void);
|
||||
void (*_xed_reserved3) (void);
|
||||
void (*_xed_reserved4) (void);
|
||||
};
|
||||
|
||||
/*
|
||||
* Public methods
|
||||
*/
|
||||
GType xed_plugin_get_type (void) G_GNUC_CONST;
|
||||
|
||||
gchar *xed_plugin_get_install_dir (XedPlugin *plugin);
|
||||
gchar *xed_plugin_get_data_dir (XedPlugin *plugin);
|
||||
|
||||
void xed_plugin_activate (XedPlugin *plugin,
|
||||
XedWindow *window);
|
||||
void xed_plugin_deactivate (XedPlugin *plugin,
|
||||
XedWindow *window);
|
||||
|
||||
void xed_plugin_update_ui (XedPlugin *plugin,
|
||||
XedWindow *window);
|
||||
|
||||
gboolean xed_plugin_is_configurable (XedPlugin *plugin);
|
||||
GtkWidget *xed_plugin_create_configure_dialog
|
||||
(XedPlugin *plugin);
|
||||
|
||||
/**
|
||||
* XED_PLUGIN_REGISTER_TYPE_WITH_CODE(PluginName, plugin_name, CODE):
|
||||
*
|
||||
* Utility macro used to register plugins with additional code.
|
||||
*/
|
||||
#define XED_PLUGIN_REGISTER_TYPE_WITH_CODE(PluginName, plugin_name, CODE) \
|
||||
G_DEFINE_DYNAMIC_TYPE_EXTENDED (PluginName, \
|
||||
plugin_name, \
|
||||
XED_TYPE_PLUGIN, \
|
||||
0, \
|
||||
GTypeModule *module G_GNUC_UNUSED = type_module; /* back compat */ \
|
||||
CODE) \
|
||||
\
|
||||
/* This is not very nice, but G_DEFINE_DYNAMIC wants it and our old macro \
|
||||
* did not support it */ \
|
||||
static void \
|
||||
plugin_name##_class_finalize (PluginName##Class *klass) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
\
|
||||
G_MODULE_EXPORT GType \
|
||||
register_xed_plugin (GTypeModule *type_module) \
|
||||
{ \
|
||||
plugin_name##_register_type (type_module); \
|
||||
\
|
||||
return plugin_name##_get_type(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* XED_PLUGIN_REGISTER_TYPE(PluginName, plugin_name):
|
||||
*
|
||||
* Utility macro used to register plugins.
|
||||
*/
|
||||
#define XED_PLUGIN_REGISTER_TYPE(PluginName, plugin_name) \
|
||||
XED_PLUGIN_REGISTER_TYPE_WITH_CODE(PluginName, plugin_name, ;)
|
||||
|
||||
/**
|
||||
* XED_PLUGIN_DEFINE_TYPE_WITH_CODE(ObjectName, object_name, PARENT_TYPE, CODE):
|
||||
*
|
||||
* Utility macro used to register gobject types in plugins with additional code.
|
||||
*
|
||||
* Deprecated: use G_DEFINE_DYNAMIC_TYPE_EXTENDED instead
|
||||
*/
|
||||
#define XED_PLUGIN_DEFINE_TYPE_WITH_CODE(ObjectName, object_name, PARENT_TYPE, CODE) \
|
||||
\
|
||||
static GType g_define_type_id = 0; \
|
||||
\
|
||||
GType \
|
||||
object_name##_get_type (void) \
|
||||
{ \
|
||||
return g_define_type_id; \
|
||||
} \
|
||||
\
|
||||
static void object_name##_init (ObjectName *self); \
|
||||
static void object_name##_class_init (ObjectName##Class *klass); \
|
||||
static gpointer object_name##_parent_class = NULL; \
|
||||
static void object_name##_class_intern_init (gpointer klass) \
|
||||
{ \
|
||||
object_name##_parent_class = g_type_class_peek_parent (klass); \
|
||||
object_name##_class_init ((ObjectName##Class *) klass); \
|
||||
} \
|
||||
\
|
||||
GType \
|
||||
object_name##_register_type (GTypeModule *type_module) \
|
||||
{ \
|
||||
GTypeModule *module G_GNUC_UNUSED = type_module; /* back compat */ \
|
||||
static const GTypeInfo our_info = \
|
||||
{ \
|
||||
sizeof (ObjectName##Class), \
|
||||
NULL, /* base_init */ \
|
||||
NULL, /* base_finalize */ \
|
||||
(GClassInitFunc) object_name##_class_intern_init, \
|
||||
NULL, \
|
||||
NULL, /* class_data */ \
|
||||
sizeof (ObjectName), \
|
||||
0, /* n_preallocs */ \
|
||||
(GInstanceInitFunc) object_name##_init \
|
||||
}; \
|
||||
\
|
||||
g_define_type_id = g_type_module_register_type (type_module, \
|
||||
PARENT_TYPE, \
|
||||
#ObjectName, \
|
||||
&our_info, \
|
||||
0); \
|
||||
\
|
||||
CODE \
|
||||
\
|
||||
return g_define_type_id; \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* XED_PLUGIN_DEFINE_TYPE(ObjectName, object_name, PARENT_TYPE):
|
||||
*
|
||||
* Utility macro used to register gobject types in plugins.
|
||||
*
|
||||
* Deprecated: use G_DEFINE_DYNAMIC instead
|
||||
*/
|
||||
#define XED_PLUGIN_DEFINE_TYPE(ObjectName, object_name, PARENT_TYPE) \
|
||||
XED_PLUGIN_DEFINE_TYPE_WITH_CODE(ObjectName, object_name, PARENT_TYPE, ;)
|
||||
|
||||
/**
|
||||
* XED_PLUGIN_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init):
|
||||
*
|
||||
* Utility macro used to register interfaces for gobject types in plugins.
|
||||
*/
|
||||
#define XED_PLUGIN_IMPLEMENT_INTERFACE(object_name, TYPE_IFACE, iface_init) \
|
||||
const GInterfaceInfo object_name##_interface_info = \
|
||||
{ \
|
||||
(GInterfaceInitFunc) iface_init, \
|
||||
NULL, \
|
||||
NULL \
|
||||
}; \
|
||||
\
|
||||
g_type_module_add_interface (type_module, \
|
||||
g_define_type_id, \
|
||||
TYPE_IFACE, \
|
||||
&object_name##_interface_info);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_PLUGIN_H__ */
|
||||
861
xed/xed-plugins-engine.c
Normal file
861
xed/xed-plugins-engine.c
Normal file
@@ -0,0 +1,861 @@
|
||||
/*
|
||||
* xed-plugins-engine.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "xed-plugins-engine.h"
|
||||
#include "xed-plugin-info-priv.h"
|
||||
#include "xed-plugin.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-app.h"
|
||||
#include "xed-prefs-manager.h"
|
||||
#include "xed-plugin-loader.h"
|
||||
#include "xed-object-module.h"
|
||||
#include "xed-dirs.h"
|
||||
|
||||
#define XED_PLUGINS_ENGINE_BASE_KEY "/apps/xed/plugins"
|
||||
#define XED_PLUGINS_ENGINE_KEY XED_PLUGINS_ENGINE_BASE_KEY "/active-plugins"
|
||||
|
||||
#define PLUGIN_EXT ".xed-plugin"
|
||||
#define LOADER_EXT G_MODULE_SUFFIX
|
||||
|
||||
typedef struct
|
||||
{
|
||||
XedPluginLoader *loader;
|
||||
XedObjectModule *module;
|
||||
} LoaderInfo;
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
ACTIVATE_PLUGIN,
|
||||
DEACTIVATE_PLUGIN,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE(XedPluginsEngine, xed_plugins_engine, G_TYPE_OBJECT)
|
||||
|
||||
struct _XedPluginsEnginePrivate
|
||||
{
|
||||
GList *plugin_list;
|
||||
GHashTable *loaders;
|
||||
|
||||
gboolean activate_from_prefs;
|
||||
};
|
||||
|
||||
XedPluginsEngine *default_engine = NULL;
|
||||
|
||||
static void xed_plugins_engine_activate_plugin_real (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info);
|
||||
static void xed_plugins_engine_deactivate_plugin_real (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info);
|
||||
|
||||
typedef gboolean (*LoadDirCallback)(XedPluginsEngine *engine, const gchar *filename, gpointer userdata);
|
||||
|
||||
static gboolean
|
||||
load_dir_real (XedPluginsEngine *engine,
|
||||
const gchar *dir,
|
||||
const gchar *suffix,
|
||||
LoadDirCallback callback,
|
||||
gpointer userdata)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GDir *d;
|
||||
const gchar *dirent;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
g_return_val_if_fail (dir != NULL, TRUE);
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "DIR: %s", dir);
|
||||
|
||||
d = g_dir_open (dir, 0, &error);
|
||||
if (!d)
|
||||
{
|
||||
g_warning ("%s", error->message);
|
||||
g_error_free (error);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
while ((dirent = g_dir_read_name (d)))
|
||||
{
|
||||
gchar *filename;
|
||||
|
||||
if (!g_str_has_suffix (dirent, suffix))
|
||||
continue;
|
||||
|
||||
filename = g_build_filename (dir, dirent, NULL);
|
||||
|
||||
ret = callback (engine, filename, userdata);
|
||||
|
||||
g_free (filename);
|
||||
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
|
||||
g_dir_close (d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_plugin_info (XedPluginsEngine *engine,
|
||||
const gchar *filename,
|
||||
gpointer userdata)
|
||||
{
|
||||
XedPluginInfo *info;
|
||||
|
||||
info = _xed_plugin_info_new (filename);
|
||||
|
||||
if (info == NULL)
|
||||
return TRUE;
|
||||
|
||||
/* If a plugin with this name has already been loaded
|
||||
* drop this one (user plugins override system plugins) */
|
||||
if (xed_plugins_engine_get_plugin_info (engine, xed_plugin_info_get_module_name (info)) != NULL)
|
||||
{
|
||||
xed_debug_message (DEBUG_PLUGINS, "Two or more plugins named '%s'. "
|
||||
"Only the first will be considered.\n",
|
||||
xed_plugin_info_get_module_name (info));
|
||||
|
||||
_xed_plugin_info_unref (info);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
engine->priv->plugin_list = g_list_prepend (engine->priv->plugin_list, info);
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "Plugin %s loaded", info->name);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
load_all_plugins (XedPluginsEngine *engine)
|
||||
{
|
||||
gchar *plugin_dir;
|
||||
const gchar *pdirs_env = NULL;
|
||||
|
||||
/* load user plugins */
|
||||
plugin_dir = xed_dirs_get_user_plugins_dir ();
|
||||
if (g_file_test (plugin_dir, G_FILE_TEST_IS_DIR))
|
||||
{
|
||||
load_dir_real (engine,
|
||||
plugin_dir,
|
||||
PLUGIN_EXT,
|
||||
load_plugin_info,
|
||||
NULL);
|
||||
|
||||
}
|
||||
g_free (plugin_dir);
|
||||
|
||||
/* load system plugins */
|
||||
pdirs_env = g_getenv ("XED_PLUGINS_PATH");
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "XED_PLUGINS_PATH=%s", pdirs_env);
|
||||
|
||||
if (pdirs_env != NULL)
|
||||
{
|
||||
gchar **pdirs;
|
||||
gint i;
|
||||
|
||||
pdirs = g_strsplit (pdirs_env, G_SEARCHPATH_SEPARATOR_S, 0);
|
||||
|
||||
for (i = 0; pdirs[i] != NULL; i++)
|
||||
{
|
||||
if (!load_dir_real (engine,
|
||||
pdirs[i],
|
||||
PLUGIN_EXT,
|
||||
load_plugin_info,
|
||||
NULL))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev (pdirs);
|
||||
}
|
||||
else
|
||||
{
|
||||
plugin_dir = xed_dirs_get_xed_plugins_dir ();
|
||||
|
||||
load_dir_real (engine,
|
||||
plugin_dir,
|
||||
PLUGIN_EXT,
|
||||
load_plugin_info,
|
||||
NULL);
|
||||
|
||||
g_free (plugin_dir);
|
||||
}
|
||||
}
|
||||
|
||||
static guint
|
||||
hash_lowercase (gconstpointer data)
|
||||
{
|
||||
gchar *lowercase;
|
||||
guint ret;
|
||||
|
||||
lowercase = g_ascii_strdown ((const gchar *)data, -1);
|
||||
ret = g_str_hash (lowercase);
|
||||
g_free (lowercase);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
equal_lowercase (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
return g_ascii_strcasecmp ((const gchar *)a, (const gchar *)b) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
loader_destroy (LoaderInfo *info)
|
||||
{
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if (info->loader)
|
||||
g_object_unref (info->loader);
|
||||
|
||||
g_free (info);
|
||||
}
|
||||
|
||||
static void
|
||||
add_loader (XedPluginsEngine *engine,
|
||||
const gchar *loader_id,
|
||||
XedObjectModule *module)
|
||||
{
|
||||
LoaderInfo *info;
|
||||
|
||||
info = g_new (LoaderInfo, 1);
|
||||
info->loader = NULL;
|
||||
info->module = module;
|
||||
|
||||
g_hash_table_insert (engine->priv->loaders, g_strdup (loader_id), info);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugins_engine_init (XedPluginsEngine *engine)
|
||||
{
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
if (!g_module_supported ())
|
||||
{
|
||||
g_warning ("xed is not able to initialize the plugins engine.");
|
||||
return;
|
||||
}
|
||||
|
||||
engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine,
|
||||
XED_TYPE_PLUGINS_ENGINE,
|
||||
XedPluginsEnginePrivate);
|
||||
|
||||
load_all_plugins (engine);
|
||||
|
||||
/* make sure that the first reactivation will read active plugins
|
||||
from the prefs */
|
||||
engine->priv->activate_from_prefs = TRUE;
|
||||
|
||||
/* mapping from loadername -> loader object */
|
||||
engine->priv->loaders = g_hash_table_new_full (hash_lowercase,
|
||||
equal_lowercase,
|
||||
(GDestroyNotify)g_free,
|
||||
(GDestroyNotify)loader_destroy);
|
||||
}
|
||||
|
||||
static void
|
||||
loader_garbage_collect (const char *id, LoaderInfo *info)
|
||||
{
|
||||
if (info->loader)
|
||||
xed_plugin_loader_garbage_collect (info->loader);
|
||||
}
|
||||
|
||||
void
|
||||
xed_plugins_engine_garbage_collect (XedPluginsEngine *engine)
|
||||
{
|
||||
g_hash_table_foreach (engine->priv->loaders,
|
||||
(GHFunc) loader_garbage_collect,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugins_engine_finalize (GObject *object)
|
||||
{
|
||||
XedPluginsEngine *engine = XED_PLUGINS_ENGINE (object);
|
||||
GList *item;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
/* Firs deactivate all plugins */
|
||||
for (item = engine->priv->plugin_list; item; item = item->next)
|
||||
{
|
||||
XedPluginInfo *info = XED_PLUGIN_INFO (item->data);
|
||||
|
||||
if (xed_plugin_info_is_active (info))
|
||||
xed_plugins_engine_deactivate_plugin_real (engine, info);
|
||||
}
|
||||
|
||||
/* unref the loaders */
|
||||
g_hash_table_destroy (engine->priv->loaders);
|
||||
|
||||
/* and finally free the infos */
|
||||
for (item = engine->priv->plugin_list; item; item = item->next)
|
||||
{
|
||||
XedPluginInfo *info = XED_PLUGIN_INFO (item->data);
|
||||
|
||||
_xed_plugin_info_unref (info);
|
||||
}
|
||||
|
||||
g_list_free (engine->priv->plugin_list);
|
||||
|
||||
G_OBJECT_CLASS (xed_plugins_engine_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugins_engine_class_init (XedPluginsEngineClass *klass)
|
||||
{
|
||||
GType the_type = G_TYPE_FROM_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = xed_plugins_engine_finalize;
|
||||
klass->activate_plugin = xed_plugins_engine_activate_plugin_real;
|
||||
klass->deactivate_plugin = xed_plugins_engine_deactivate_plugin_real;
|
||||
|
||||
signals[ACTIVATE_PLUGIN] =
|
||||
g_signal_new ("activate-plugin",
|
||||
the_type,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (XedPluginsEngineClass, activate_plugin),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__BOXED,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
XED_TYPE_PLUGIN_INFO | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
|
||||
signals[DEACTIVATE_PLUGIN] =
|
||||
g_signal_new ("deactivate-plugin",
|
||||
the_type,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (XedPluginsEngineClass, deactivate_plugin),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__BOXED,
|
||||
G_TYPE_NONE,
|
||||
1,
|
||||
XED_TYPE_PLUGIN_INFO | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (XedPluginsEnginePrivate));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_loader (XedPluginsEngine *engine,
|
||||
const gchar *filename,
|
||||
gpointer data)
|
||||
{
|
||||
XedObjectModule *module;
|
||||
gchar *base;
|
||||
gchar *path;
|
||||
const gchar *id;
|
||||
GType type;
|
||||
|
||||
/* try to load in the module */
|
||||
path = g_path_get_dirname (filename);
|
||||
base = g_path_get_basename (filename);
|
||||
|
||||
/* for now they are all resident */
|
||||
module = xed_object_module_new (base,
|
||||
path,
|
||||
"register_xed_plugin_loader",
|
||||
TRUE);
|
||||
|
||||
g_free (base);
|
||||
g_free (path);
|
||||
|
||||
/* make sure to load the type definition */
|
||||
if (!g_type_module_use (G_TYPE_MODULE (module)))
|
||||
{
|
||||
g_object_unref (module);
|
||||
g_warning ("Plugin loader module `%s' could not be loaded", filename);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* get the exported type and check the name as exported by the
|
||||
* loader interface */
|
||||
type = xed_object_module_get_object_type (module);
|
||||
id = xed_plugin_loader_type_get_id (type);
|
||||
|
||||
add_loader (engine, id, module);
|
||||
g_type_module_unuse (G_TYPE_MODULE (module));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_loader (LoaderInfo *info)
|
||||
{
|
||||
if (info->loader == NULL && info->module != NULL)
|
||||
{
|
||||
/* create a new loader object */
|
||||
XedPluginLoader *loader;
|
||||
loader = (XedPluginLoader *)xed_object_module_new_object (info->module, NULL);
|
||||
|
||||
if (loader == NULL || !XED_IS_PLUGIN_LOADER (loader))
|
||||
{
|
||||
g_warning ("Loader object is not a valid XedPluginLoader instance");
|
||||
|
||||
if (loader != NULL && G_IS_OBJECT (loader))
|
||||
g_object_unref (loader);
|
||||
}
|
||||
else
|
||||
{
|
||||
info->loader = loader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static XedPluginLoader *
|
||||
get_plugin_loader (XedPluginsEngine *engine, XedPluginInfo *info)
|
||||
{
|
||||
const gchar *loader_id;
|
||||
LoaderInfo *loader_info;
|
||||
|
||||
loader_id = info->loader;
|
||||
|
||||
loader_info = (LoaderInfo *)g_hash_table_lookup (
|
||||
engine->priv->loaders,
|
||||
loader_id);
|
||||
|
||||
if (loader_info == NULL)
|
||||
{
|
||||
gchar *loader_dir;
|
||||
|
||||
loader_dir = xed_dirs_get_xed_plugin_loaders_dir ();
|
||||
|
||||
/* loader could not be found in the hash, try to find it by
|
||||
scanning */
|
||||
load_dir_real (engine,
|
||||
loader_dir,
|
||||
LOADER_EXT,
|
||||
(LoadDirCallback)load_loader,
|
||||
NULL);
|
||||
g_free (loader_dir);
|
||||
|
||||
loader_info = (LoaderInfo *)g_hash_table_lookup (
|
||||
engine->priv->loaders,
|
||||
loader_id);
|
||||
}
|
||||
|
||||
if (loader_info == NULL)
|
||||
{
|
||||
/* cache non-existent so we don't scan again */
|
||||
add_loader (engine, loader_id, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ensure_loader (loader_info);
|
||||
return loader_info->loader;
|
||||
}
|
||||
|
||||
XedPluginsEngine *
|
||||
xed_plugins_engine_get_default (void)
|
||||
{
|
||||
if (default_engine != NULL)
|
||||
return default_engine;
|
||||
|
||||
default_engine = XED_PLUGINS_ENGINE (g_object_new (XED_TYPE_PLUGINS_ENGINE, NULL));
|
||||
g_object_add_weak_pointer (G_OBJECT (default_engine),
|
||||
(gpointer) &default_engine);
|
||||
return default_engine;
|
||||
}
|
||||
|
||||
const GList *
|
||||
xed_plugins_engine_get_plugin_list (XedPluginsEngine *engine)
|
||||
{
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
return engine->priv->plugin_list;
|
||||
}
|
||||
|
||||
static gint
|
||||
compare_plugin_info_and_name (XedPluginInfo *info,
|
||||
const gchar *module_name)
|
||||
{
|
||||
return strcmp (xed_plugin_info_get_module_name (info), module_name);
|
||||
}
|
||||
|
||||
XedPluginInfo *
|
||||
xed_plugins_engine_get_plugin_info (XedPluginsEngine *engine,
|
||||
const gchar *name)
|
||||
{
|
||||
GList *l = g_list_find_custom (engine->priv->plugin_list,
|
||||
name,
|
||||
(GCompareFunc) compare_plugin_info_and_name);
|
||||
|
||||
return l == NULL ? NULL : (XedPluginInfo *) l->data;
|
||||
}
|
||||
|
||||
static void
|
||||
save_active_plugin_list (XedPluginsEngine *engine)
|
||||
{
|
||||
GSList *active_plugins = NULL;
|
||||
GList *l;
|
||||
|
||||
for (l = engine->priv->plugin_list; l != NULL; l = l->next)
|
||||
{
|
||||
XedPluginInfo *info = (XedPluginInfo *) l->data;
|
||||
|
||||
if (xed_plugin_info_is_active (info))
|
||||
{
|
||||
active_plugins = g_slist_prepend (active_plugins,
|
||||
(gpointer)xed_plugin_info_get_module_name (info));
|
||||
}
|
||||
}
|
||||
|
||||
xed_prefs_manager_set_active_plugins (active_plugins);
|
||||
|
||||
g_slist_free (active_plugins);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_plugin (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info)
|
||||
{
|
||||
XedPluginLoader *loader;
|
||||
gchar *path;
|
||||
|
||||
if (xed_plugin_info_is_active (info))
|
||||
return TRUE;
|
||||
|
||||
if (!xed_plugin_info_is_available (info))
|
||||
return FALSE;
|
||||
|
||||
loader = get_plugin_loader (engine, info);
|
||||
|
||||
if (loader == NULL)
|
||||
{
|
||||
g_warning ("Could not find loader `%s' for plugin `%s'", info->loader, info->name);
|
||||
info->available = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
path = g_path_get_dirname (info->file);
|
||||
g_return_val_if_fail (path != NULL, FALSE);
|
||||
|
||||
info->plugin = xed_plugin_loader_load (loader, info, path);
|
||||
|
||||
g_free (path);
|
||||
|
||||
if (info->plugin == NULL)
|
||||
{
|
||||
g_warning ("Error loading plugin '%s'", info->name);
|
||||
info->available = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugins_engine_activate_plugin_real (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info)
|
||||
{
|
||||
const GList *wins;
|
||||
|
||||
if (!load_plugin (engine, info))
|
||||
return;
|
||||
|
||||
for (wins = xed_app_get_windows (xed_app_get_default ());
|
||||
wins != NULL;
|
||||
wins = wins->next)
|
||||
{
|
||||
xed_plugin_activate (info->plugin, XED_WINDOW (wins->data));
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_plugins_engine_activate_plugin (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info)
|
||||
{
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
g_return_val_if_fail (info != NULL, FALSE);
|
||||
|
||||
if (!xed_plugin_info_is_available (info))
|
||||
return FALSE;
|
||||
|
||||
if (xed_plugin_info_is_active (info))
|
||||
return TRUE;
|
||||
|
||||
g_signal_emit (engine, signals[ACTIVATE_PLUGIN], 0, info);
|
||||
|
||||
if (xed_plugin_info_is_active (info))
|
||||
save_active_plugin_list (engine);
|
||||
|
||||
return xed_plugin_info_is_active (info);
|
||||
}
|
||||
|
||||
static void
|
||||
call_plugin_deactivate (XedPlugin *plugin,
|
||||
XedWindow *window)
|
||||
{
|
||||
xed_plugin_deactivate (plugin, window);
|
||||
|
||||
/* ensure update of ui manager, because we suspect it does something
|
||||
with expected static strings in the type module (when unloaded the
|
||||
strings don't exist anymore, and ui manager updates in an idle
|
||||
func) */
|
||||
gtk_ui_manager_ensure_update (xed_window_get_ui_manager (window));
|
||||
}
|
||||
|
||||
static void
|
||||
xed_plugins_engine_deactivate_plugin_real (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info)
|
||||
{
|
||||
const GList *wins;
|
||||
XedPluginLoader *loader;
|
||||
|
||||
if (!xed_plugin_info_is_active (info) ||
|
||||
!xed_plugin_info_is_available (info))
|
||||
return;
|
||||
|
||||
for (wins = xed_app_get_windows (xed_app_get_default ());
|
||||
wins != NULL;
|
||||
wins = wins->next)
|
||||
{
|
||||
call_plugin_deactivate (info->plugin, XED_WINDOW (wins->data));
|
||||
}
|
||||
|
||||
/* first unref the plugin (the loader still has one) */
|
||||
g_object_unref (info->plugin);
|
||||
|
||||
/* find the loader and tell it to gc and unload the plugin */
|
||||
loader = get_plugin_loader (engine, info);
|
||||
|
||||
xed_plugin_loader_garbage_collect (loader);
|
||||
xed_plugin_loader_unload (loader, info);
|
||||
|
||||
info->plugin = NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_plugins_engine_deactivate_plugin (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info)
|
||||
{
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
g_return_val_if_fail (info != NULL, FALSE);
|
||||
|
||||
if (!xed_plugin_info_is_active (info))
|
||||
return TRUE;
|
||||
|
||||
g_signal_emit (engine, signals[DEACTIVATE_PLUGIN], 0, info);
|
||||
if (!xed_plugin_info_is_active (info))
|
||||
save_active_plugin_list (engine);
|
||||
|
||||
return !xed_plugin_info_is_active (info);
|
||||
}
|
||||
|
||||
void
|
||||
xed_plugins_engine_activate_plugins (XedPluginsEngine *engine,
|
||||
XedWindow *window)
|
||||
{
|
||||
GSList *active_plugins = NULL;
|
||||
GList *pl;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
g_return_if_fail (XED_IS_PLUGINS_ENGINE (engine));
|
||||
g_return_if_fail (XED_IS_WINDOW (window));
|
||||
|
||||
/* the first time, we get the 'active' plugins from GSettings */
|
||||
if (engine->priv->activate_from_prefs)
|
||||
{
|
||||
active_plugins = xed_prefs_manager_get_active_plugins ();
|
||||
}
|
||||
|
||||
for (pl = engine->priv->plugin_list; pl; pl = pl->next)
|
||||
{
|
||||
XedPluginInfo *info = (XedPluginInfo*)pl->data;
|
||||
|
||||
if (engine->priv->activate_from_prefs &&
|
||||
g_slist_find_custom (active_plugins,
|
||||
xed_plugin_info_get_module_name (info),
|
||||
(GCompareFunc)strcmp) == NULL)
|
||||
continue;
|
||||
|
||||
/* If plugin is not active, don't try to activate/load it */
|
||||
if (!engine->priv->activate_from_prefs &&
|
||||
!xed_plugin_info_is_active (info))
|
||||
continue;
|
||||
|
||||
if (load_plugin (engine, info))
|
||||
xed_plugin_activate (info->plugin,
|
||||
window);
|
||||
}
|
||||
|
||||
if (engine->priv->activate_from_prefs)
|
||||
{
|
||||
g_slist_foreach (active_plugins, (GFunc) g_free, NULL);
|
||||
g_slist_free (active_plugins);
|
||||
engine->priv->activate_from_prefs = FALSE;
|
||||
}
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "End");
|
||||
|
||||
/* also call update_ui after activation */
|
||||
xed_plugins_engine_update_plugins_ui (engine, window);
|
||||
}
|
||||
|
||||
void
|
||||
xed_plugins_engine_deactivate_plugins (XedPluginsEngine *engine,
|
||||
XedWindow *window)
|
||||
{
|
||||
GList *pl;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
g_return_if_fail (XED_IS_PLUGINS_ENGINE (engine));
|
||||
g_return_if_fail (XED_IS_WINDOW (window));
|
||||
|
||||
for (pl = engine->priv->plugin_list; pl; pl = pl->next)
|
||||
{
|
||||
XedPluginInfo *info = (XedPluginInfo*)pl->data;
|
||||
|
||||
/* check if the plugin is actually active */
|
||||
if (!xed_plugin_info_is_active (info))
|
||||
continue;
|
||||
|
||||
/* call deactivate for the plugin for this window */
|
||||
xed_plugin_deactivate (info->plugin, window);
|
||||
}
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "End");
|
||||
}
|
||||
|
||||
void
|
||||
xed_plugins_engine_update_plugins_ui (XedPluginsEngine *engine,
|
||||
XedWindow *window)
|
||||
{
|
||||
GList *pl;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
g_return_if_fail (XED_IS_PLUGINS_ENGINE (engine));
|
||||
g_return_if_fail (XED_IS_WINDOW (window));
|
||||
|
||||
/* call update_ui for all active plugins */
|
||||
for (pl = engine->priv->plugin_list; pl; pl = pl->next)
|
||||
{
|
||||
XedPluginInfo *info = (XedPluginInfo*)pl->data;
|
||||
|
||||
if (!xed_plugin_info_is_active (info))
|
||||
continue;
|
||||
|
||||
xed_debug_message (DEBUG_PLUGINS, "Updating UI of %s", info->name);
|
||||
xed_plugin_update_ui (info->plugin, window);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xed_plugins_engine_configure_plugin (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info,
|
||||
GtkWindow *parent)
|
||||
{
|
||||
GtkWidget *conf_dlg;
|
||||
|
||||
GtkWindowGroup *wg;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
g_return_if_fail (info != NULL);
|
||||
|
||||
conf_dlg = xed_plugin_create_configure_dialog (info->plugin);
|
||||
g_return_if_fail (conf_dlg != NULL);
|
||||
gtk_window_set_transient_for (GTK_WINDOW (conf_dlg),
|
||||
parent);
|
||||
|
||||
wg = gtk_window_get_group (parent);
|
||||
if (wg == NULL)
|
||||
{
|
||||
wg = gtk_window_group_new ();
|
||||
gtk_window_group_add_window (wg, parent);
|
||||
}
|
||||
|
||||
gtk_window_group_add_window (wg,
|
||||
GTK_WINDOW (conf_dlg));
|
||||
|
||||
gtk_window_set_modal (GTK_WINDOW (conf_dlg), TRUE);
|
||||
gtk_widget_show (conf_dlg);
|
||||
}
|
||||
|
||||
void
|
||||
xed_plugins_engine_active_plugins_changed (XedPluginsEngine *engine)
|
||||
{
|
||||
gboolean to_activate;
|
||||
GSList *active_plugins;
|
||||
GList *pl;
|
||||
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
active_plugins = xed_prefs_manager_get_active_plugins ();
|
||||
|
||||
for (pl = engine->priv->plugin_list; pl; pl = pl->next)
|
||||
{
|
||||
XedPluginInfo *info = (XedPluginInfo*)pl->data;
|
||||
|
||||
if (!xed_plugin_info_is_available (info))
|
||||
continue;
|
||||
|
||||
to_activate = (g_slist_find_custom (active_plugins,
|
||||
xed_plugin_info_get_module_name (info),
|
||||
(GCompareFunc)strcmp) != NULL);
|
||||
|
||||
if (!xed_plugin_info_is_active (info) && to_activate)
|
||||
g_signal_emit (engine, signals[ACTIVATE_PLUGIN], 0, info);
|
||||
else if (xed_plugin_info_is_active (info) && !to_activate)
|
||||
g_signal_emit (engine, signals[DEACTIVATE_PLUGIN], 0, info);
|
||||
}
|
||||
|
||||
g_slist_foreach (active_plugins, (GFunc) g_free, NULL);
|
||||
g_slist_free (active_plugins);
|
||||
}
|
||||
|
||||
void
|
||||
xed_plugins_engine_rescan_plugins (XedPluginsEngine *engine)
|
||||
{
|
||||
xed_debug (DEBUG_PLUGINS);
|
||||
|
||||
load_all_plugins (engine);
|
||||
}
|
||||
107
xed/xed-plugins-engine.h
Normal file
107
xed/xed-plugins-engine.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* xed-plugins-engine.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 - Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __XED_PLUGINS_ENGINE_H__
|
||||
#define __XED_PLUGINS_ENGINE_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include "xed-window.h"
|
||||
#include "xed-plugin-info.h"
|
||||
#include "xed-plugin.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XED_TYPE_PLUGINS_ENGINE (xed_plugins_engine_get_type ())
|
||||
#define XED_PLUGINS_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XED_TYPE_PLUGINS_ENGINE, XedPluginsEngine))
|
||||
#define XED_PLUGINS_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), XED_TYPE_PLUGINS_ENGINE, XedPluginsEngineClass))
|
||||
#define XED_IS_PLUGINS_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), XED_TYPE_PLUGINS_ENGINE))
|
||||
#define XED_IS_PLUGINS_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_PLUGINS_ENGINE))
|
||||
#define XED_PLUGINS_ENGINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), XED_TYPE_PLUGINS_ENGINE, XedPluginsEngineClass))
|
||||
|
||||
typedef struct _XedPluginsEngine XedPluginsEngine;
|
||||
typedef struct _XedPluginsEnginePrivate XedPluginsEnginePrivate;
|
||||
|
||||
struct _XedPluginsEngine
|
||||
{
|
||||
GObject parent;
|
||||
XedPluginsEnginePrivate *priv;
|
||||
};
|
||||
|
||||
typedef struct _XedPluginsEngineClass XedPluginsEngineClass;
|
||||
|
||||
struct _XedPluginsEngineClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* activate_plugin) (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info);
|
||||
|
||||
void (* deactivate_plugin) (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info);
|
||||
};
|
||||
|
||||
GType xed_plugins_engine_get_type (void) G_GNUC_CONST;
|
||||
|
||||
XedPluginsEngine *xed_plugins_engine_get_default (void);
|
||||
|
||||
void xed_plugins_engine_garbage_collect (XedPluginsEngine *engine);
|
||||
|
||||
const GList *xed_plugins_engine_get_plugin_list (XedPluginsEngine *engine);
|
||||
|
||||
XedPluginInfo *xed_plugins_engine_get_plugin_info (XedPluginsEngine *engine,
|
||||
const gchar *name);
|
||||
|
||||
/* plugin load and unloading (overall, for all windows) */
|
||||
gboolean xed_plugins_engine_activate_plugin (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info);
|
||||
gboolean xed_plugins_engine_deactivate_plugin (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info);
|
||||
|
||||
void xed_plugins_engine_configure_plugin (XedPluginsEngine *engine,
|
||||
XedPluginInfo *info,
|
||||
GtkWindow *parent);
|
||||
|
||||
/* plugin activation/deactivation per window, private to XedWindow */
|
||||
void xed_plugins_engine_activate_plugins (XedPluginsEngine *engine,
|
||||
XedWindow *window);
|
||||
void xed_plugins_engine_deactivate_plugins (XedPluginsEngine *engine,
|
||||
XedWindow *window);
|
||||
void xed_plugins_engine_update_plugins_ui (XedPluginsEngine *engine,
|
||||
XedWindow *window);
|
||||
|
||||
/* private for GSettings notification */
|
||||
void xed_plugins_engine_active_plugins_changed
|
||||
(XedPluginsEngine *engine);
|
||||
|
||||
void xed_plugins_engine_rescan_plugins (XedPluginsEngine *engine);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __XED_PLUGINS_ENGINE_H__ */
|
||||
1432
xed/xed-prefs-manager-app.c
Normal file
1432
xed/xed-prefs-manager-app.c
Normal file
File diff suppressed because it is too large
Load Diff
84
xed/xed-prefs-manager-app.h
Normal file
84
xed/xed-prefs-manager-app.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* xed-prefs-manager-app.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002-2005 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002-2005. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __XED_PREFS_MANAGER_APP_H__
|
||||
#define __XED_PREFS_MANAGER_APP_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <xed/xed-prefs-manager.h>
|
||||
|
||||
/** LIFE CYCLE MANAGEMENT FUNCTIONS **/
|
||||
|
||||
gboolean xed_prefs_manager_app_init (void);
|
||||
|
||||
/* This function must be called before exiting xed */
|
||||
void xed_prefs_manager_app_shutdown (void);
|
||||
|
||||
|
||||
/* Window state */
|
||||
gint xed_prefs_manager_get_window_state (void);
|
||||
void xed_prefs_manager_set_window_state (gint ws);
|
||||
gboolean xed_prefs_manager_window_state_can_set (void);
|
||||
|
||||
/* Window size */
|
||||
void xed_prefs_manager_get_window_size (gint *width,
|
||||
gint *height);
|
||||
void xed_prefs_manager_get_default_window_size (gint *width,
|
||||
gint *height);
|
||||
void xed_prefs_manager_set_window_size (gint width,
|
||||
gint height);
|
||||
gboolean xed_prefs_manager_window_size_can_set (void);
|
||||
|
||||
/* Side panel */
|
||||
gint xed_prefs_manager_get_side_panel_size (void);
|
||||
gint xed_prefs_manager_get_default_side_panel_size(void);
|
||||
void xed_prefs_manager_set_side_panel_size (gint ps);
|
||||
gboolean xed_prefs_manager_side_panel_size_can_set (void);
|
||||
gint xed_prefs_manager_get_side_panel_active_page (void);
|
||||
void xed_prefs_manager_set_side_panel_active_page (gint id);
|
||||
gboolean xed_prefs_manager_side_panel_active_page_can_set (void);
|
||||
|
||||
/* Bottom panel */
|
||||
gint xed_prefs_manager_get_bottom_panel_size (void);
|
||||
gint xed_prefs_manager_get_default_bottom_panel_size(void);
|
||||
void xed_prefs_manager_set_bottom_panel_size (gint ps);
|
||||
gboolean xed_prefs_manager_bottom_panel_size_can_set (void);
|
||||
gint xed_prefs_manager_get_bottom_panel_active_page (void);
|
||||
void xed_prefs_manager_set_bottom_panel_active_page (gint id);
|
||||
gboolean xed_prefs_manager_bottom_panel_active_page_can_set (void);
|
||||
|
||||
/* File filter */
|
||||
gint xed_prefs_manager_get_active_file_filter (void);
|
||||
void xed_prefs_manager_set_active_file_filter (gint id);
|
||||
gboolean xed_prefs_manager_active_file_filter_can_set (void);
|
||||
|
||||
|
||||
#endif /* __XED_PREFS_MANAGER_APP_H__ */
|
||||
46
xed/xed-prefs-manager-private.h
Normal file
46
xed/xed-prefs-manager-private.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* xed-prefs-manager-private.h
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*/
|
||||
|
||||
#ifndef __XED_PREFS_MANAGER_PRIVATE_H__
|
||||
#define __XED_PREFS_MANAGER_PRIVATE_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
typedef struct _XedPrefsManager XedPrefsManager;
|
||||
|
||||
struct _XedPrefsManager {
|
||||
GSettings *settings;
|
||||
GSettings *interface_settings;
|
||||
};
|
||||
|
||||
extern XedPrefsManager *xed_prefs_manager;
|
||||
|
||||
#endif /* __XED_PREFS_MANAGER_PRIVATE_H__ */
|
||||
|
||||
|
||||
916
xed/xed-prefs-manager.c
Normal file
916
xed/xed-prefs-manager.c
Normal file
@@ -0,0 +1,916 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* xed-prefs-manager.c
|
||||
* This file is part of xed
|
||||
*
|
||||
* Copyright (C) 2002 Paolo Maggi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the xed Team, 2002. See the AUTHORS file for a
|
||||
* list of people on the xed Team.
|
||||
* See the ChangeLog files for a list of changes.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "xed-prefs-manager.h"
|
||||
#include "xed-prefs-manager-private.h"
|
||||
#include "xed-debug.h"
|
||||
#include "xed-encodings.h"
|
||||
#include "xed-utils.h"
|
||||
|
||||
#define DEFINE_BOOL_PREF(name, key) gboolean \
|
||||
xed_prefs_manager_get_ ## name (void) \
|
||||
{ \
|
||||
xed_debug (DEBUG_PREFS); \
|
||||
\
|
||||
return xed_prefs_manager_get_bool (key); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
xed_prefs_manager_set_ ## name (gboolean v) \
|
||||
{ \
|
||||
xed_debug (DEBUG_PREFS); \
|
||||
\
|
||||
xed_prefs_manager_set_bool (key, \
|
||||
v); \
|
||||
} \
|
||||
\
|
||||
gboolean \
|
||||
xed_prefs_manager_ ## name ## _can_set (void) \
|
||||
{ \
|
||||
xed_debug (DEBUG_PREFS); \
|
||||
\
|
||||
return xed_prefs_manager_key_is_writable (key); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define DEFINE_INT_PREF(name, key) gint \
|
||||
xed_prefs_manager_get_ ## name (void) \
|
||||
{ \
|
||||
xed_debug (DEBUG_PREFS); \
|
||||
\
|
||||
return xed_prefs_manager_get_int (key); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
xed_prefs_manager_set_ ## name (gint v) \
|
||||
{ \
|
||||
xed_debug (DEBUG_PREFS); \
|
||||
\
|
||||
xed_prefs_manager_set_int (key, \
|
||||
v); \
|
||||
} \
|
||||
\
|
||||
gboolean \
|
||||
xed_prefs_manager_ ## name ## _can_set (void) \
|
||||
{ \
|
||||
xed_debug (DEBUG_PREFS); \
|
||||
\
|
||||
return xed_prefs_manager_key_is_writable (key); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define DEFINE_STRING_PREF(name, key) gchar* \
|
||||
xed_prefs_manager_get_ ## name (void) \
|
||||
{ \
|
||||
xed_debug (DEBUG_PREFS); \
|
||||
\
|
||||
return xed_prefs_manager_get_string (key); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
xed_prefs_manager_set_ ## name (const gchar* v) \
|
||||
{ \
|
||||
xed_debug (DEBUG_PREFS); \
|
||||
\
|
||||
xed_prefs_manager_set_string (key, \
|
||||
v); \
|
||||
} \
|
||||
\
|
||||
gboolean \
|
||||
xed_prefs_manager_ ## name ## _can_set (void) \
|
||||
{ \
|
||||
xed_debug (DEBUG_PREFS); \
|
||||
\
|
||||
return xed_prefs_manager_key_is_writable (key); \
|
||||
}
|
||||
|
||||
|
||||
XedPrefsManager *xed_prefs_manager = NULL;
|
||||
|
||||
|
||||
static GtkWrapMode get_wrap_mode_from_string (const gchar* str);
|
||||
|
||||
static gboolean xed_prefs_manager_get_bool (const gchar* key);
|
||||
|
||||
static gint xed_prefs_manager_get_int (const gchar* key);
|
||||
|
||||
static gchar *xed_prefs_manager_get_string (const gchar* key);
|
||||
|
||||
|
||||
gboolean
|
||||
xed_prefs_manager_init (void)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
if (xed_prefs_manager == NULL)
|
||||
{
|
||||
xed_prefs_manager = g_new0 (XedPrefsManager, 1);
|
||||
xed_prefs_manager->settings = g_settings_new (XED_SCHEMA);
|
||||
xed_prefs_manager->interface_settings = g_settings_new (GPM_INTERFACE_SCHEMA);
|
||||
}
|
||||
|
||||
return xed_prefs_manager != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
xed_prefs_manager_shutdown (void)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
g_return_if_fail (xed_prefs_manager != NULL);
|
||||
|
||||
g_object_unref (xed_prefs_manager->settings);
|
||||
xed_prefs_manager->settings = NULL;
|
||||
g_object_unref (xed_prefs_manager->interface_settings);
|
||||
xed_prefs_manager->interface_settings = NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xed_prefs_manager_get_bool (const gchar* key)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return g_settings_get_boolean (xed_prefs_manager->settings, key);
|
||||
}
|
||||
|
||||
static gint
|
||||
xed_prefs_manager_get_int (const gchar* key)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return g_settings_get_int (xed_prefs_manager->settings, key);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
xed_prefs_manager_get_string (const gchar* key)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return g_settings_get_string (xed_prefs_manager->settings, key);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_prefs_manager_set_bool (const gchar* key, gboolean value)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
g_return_if_fail (g_settings_is_writable (
|
||||
xed_prefs_manager->settings, key));
|
||||
|
||||
g_settings_set_boolean (xed_prefs_manager->settings, key, value);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_prefs_manager_set_int (const gchar* key, gint value)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
g_return_if_fail (g_settings_is_writable (
|
||||
xed_prefs_manager->settings, key));
|
||||
|
||||
g_settings_set_int (xed_prefs_manager->settings, key, value);
|
||||
}
|
||||
|
||||
static void
|
||||
xed_prefs_manager_set_string (const gchar* key, const gchar* value)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
g_return_if_fail (value != NULL);
|
||||
|
||||
g_return_if_fail (g_settings_is_writable (
|
||||
xed_prefs_manager->settings, key));
|
||||
|
||||
g_settings_set_string (xed_prefs_manager->settings, key, value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xed_prefs_manager_key_is_writable (const gchar* key)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
g_return_val_if_fail (xed_prefs_manager != NULL, FALSE);
|
||||
g_return_val_if_fail (xed_prefs_manager->settings != NULL, FALSE);
|
||||
|
||||
return g_settings_is_writable (xed_prefs_manager->settings, key);
|
||||
}
|
||||
|
||||
/* Use default font */
|
||||
DEFINE_BOOL_PREF (use_default_font,
|
||||
GPM_USE_DEFAULT_FONT)
|
||||
|
||||
/* Editor font */
|
||||
DEFINE_STRING_PREF (editor_font,
|
||||
GPM_EDITOR_FONT)
|
||||
|
||||
/* System font */
|
||||
gchar *
|
||||
xed_prefs_manager_get_system_font (void)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return g_settings_get_string (xed_prefs_manager->interface_settings,
|
||||
GPM_SYSTEM_FONT);
|
||||
}
|
||||
|
||||
/* Create backup copy */
|
||||
DEFINE_BOOL_PREF (create_backup_copy,
|
||||
GPM_CREATE_BACKUP_COPY)
|
||||
|
||||
/* Auto save */
|
||||
DEFINE_BOOL_PREF (auto_save,
|
||||
GPM_AUTO_SAVE)
|
||||
|
||||
/* Auto save interval */
|
||||
DEFINE_INT_PREF (auto_save_interval,
|
||||
GPM_AUTO_SAVE_INTERVAL)
|
||||
|
||||
|
||||
/* Undo actions limit: if < 1 then no limits */
|
||||
DEFINE_INT_PREF (undo_actions_limit,
|
||||
GPM_UNDO_ACTIONS_LIMIT)
|
||||
|
||||
static GtkWrapMode
|
||||
get_wrap_mode_from_string (const gchar* str)
|
||||
{
|
||||
GtkWrapMode res;
|
||||
|
||||
g_return_val_if_fail (str != NULL, GTK_WRAP_WORD);
|
||||
|
||||
if (strcmp (str, "GTK_WRAP_NONE") == 0)
|
||||
res = GTK_WRAP_NONE;
|
||||
else
|
||||
{
|
||||
if (strcmp (str, "GTK_WRAP_CHAR") == 0)
|
||||
res = GTK_WRAP_CHAR;
|
||||
else
|
||||
res = GTK_WRAP_WORD;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Wrap mode */
|
||||
GtkWrapMode
|
||||
xed_prefs_manager_get_wrap_mode (void)
|
||||
{
|
||||
gchar *str;
|
||||
GtkWrapMode res;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
str = xed_prefs_manager_get_string (GPM_WRAP_MODE);
|
||||
|
||||
res = get_wrap_mode_from_string (str);
|
||||
|
||||
g_free (str);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
xed_prefs_manager_set_wrap_mode (GtkWrapMode wp)
|
||||
{
|
||||
const gchar * str;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
switch (wp)
|
||||
{
|
||||
case GTK_WRAP_NONE:
|
||||
str = "GTK_WRAP_NONE";
|
||||
break;
|
||||
|
||||
case GTK_WRAP_CHAR:
|
||||
str = "GTK_WRAP_CHAR";
|
||||
break;
|
||||
|
||||
default: /* GTK_WRAP_WORD */
|
||||
str = "GTK_WRAP_WORD";
|
||||
}
|
||||
|
||||
xed_prefs_manager_set_string (GPM_WRAP_MODE,
|
||||
str);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_prefs_manager_wrap_mode_can_set (void)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return xed_prefs_manager_key_is_writable (GPM_WRAP_MODE);
|
||||
}
|
||||
|
||||
|
||||
/* Tabs size */
|
||||
DEFINE_INT_PREF (tabs_size,
|
||||
GPM_TABS_SIZE)
|
||||
|
||||
/* Insert spaces */
|
||||
DEFINE_BOOL_PREF (insert_spaces,
|
||||
GPM_INSERT_SPACES)
|
||||
|
||||
/* Auto indent */
|
||||
DEFINE_BOOL_PREF (auto_indent,
|
||||
GPM_AUTO_INDENT)
|
||||
|
||||
/* Display line numbers */
|
||||
DEFINE_BOOL_PREF (display_line_numbers,
|
||||
GPM_DISPLAY_LINE_NUMBERS)
|
||||
|
||||
/* Toolbar visibility */
|
||||
DEFINE_BOOL_PREF (toolbar_visible,
|
||||
GPM_TOOLBAR_VISIBLE)
|
||||
|
||||
|
||||
/* Toolbar suttons style */
|
||||
XedToolbarSetting
|
||||
xed_prefs_manager_get_toolbar_buttons_style (void)
|
||||
{
|
||||
gchar *str;
|
||||
XedToolbarSetting res;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
str = xed_prefs_manager_get_string (GPM_TOOLBAR_BUTTONS_STYLE);
|
||||
|
||||
if (strcmp (str, "XED_TOOLBAR_ICONS") == 0)
|
||||
res = XED_TOOLBAR_ICONS;
|
||||
else
|
||||
{
|
||||
if (strcmp (str, "XED_TOOLBAR_ICONS_AND_TEXT") == 0)
|
||||
res = XED_TOOLBAR_ICONS_AND_TEXT;
|
||||
else
|
||||
{
|
||||
if (strcmp (str, "XED_TOOLBAR_ICONS_BOTH_HORIZ") == 0)
|
||||
res = XED_TOOLBAR_ICONS_BOTH_HORIZ;
|
||||
else
|
||||
res = XED_TOOLBAR_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (str);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
xed_prefs_manager_set_toolbar_buttons_style (XedToolbarSetting tbs)
|
||||
{
|
||||
const gchar * str;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
switch (tbs)
|
||||
{
|
||||
case XED_TOOLBAR_ICONS:
|
||||
str = "XED_TOOLBAR_ICONS";
|
||||
break;
|
||||
|
||||
case XED_TOOLBAR_ICONS_AND_TEXT:
|
||||
str = "XED_TOOLBAR_ICONS_AND_TEXT";
|
||||
break;
|
||||
|
||||
case XED_TOOLBAR_ICONS_BOTH_HORIZ:
|
||||
str = "XED_TOOLBAR_ICONS_BOTH_HORIZ";
|
||||
break;
|
||||
default: /* XED_TOOLBAR_SYSTEM */
|
||||
str = "XED_TOOLBAR_SYSTEM";
|
||||
}
|
||||
|
||||
xed_prefs_manager_set_string (GPM_TOOLBAR_BUTTONS_STYLE,
|
||||
str);
|
||||
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_prefs_manager_toolbar_buttons_style_can_set (void)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return xed_prefs_manager_key_is_writable (GPM_TOOLBAR_BUTTONS_STYLE);
|
||||
|
||||
}
|
||||
|
||||
/* Statusbar visiblity */
|
||||
DEFINE_BOOL_PREF (statusbar_visible,
|
||||
GPM_STATUSBAR_VISIBLE)
|
||||
|
||||
/* Side Pane visiblity */
|
||||
DEFINE_BOOL_PREF (side_pane_visible,
|
||||
GPM_SIDE_PANE_VISIBLE)
|
||||
|
||||
/* Bottom Panel visiblity */
|
||||
DEFINE_BOOL_PREF (bottom_panel_visible,
|
||||
GPM_BOTTOM_PANEL_VISIBLE)
|
||||
|
||||
/* Print syntax highlighting */
|
||||
DEFINE_BOOL_PREF (print_syntax_hl,
|
||||
GPM_PRINT_SYNTAX)
|
||||
|
||||
/* Print header */
|
||||
DEFINE_BOOL_PREF (print_header,
|
||||
GPM_PRINT_HEADER)
|
||||
|
||||
|
||||
/* Print Wrap mode */
|
||||
GtkWrapMode
|
||||
xed_prefs_manager_get_print_wrap_mode (void)
|
||||
{
|
||||
gchar *str;
|
||||
GtkWrapMode res;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
str = xed_prefs_manager_get_string (GPM_PRINT_WRAP_MODE);
|
||||
|
||||
if (strcmp (str, "GTK_WRAP_NONE") == 0)
|
||||
res = GTK_WRAP_NONE;
|
||||
else
|
||||
{
|
||||
if (strcmp (str, "GTK_WRAP_WORD") == 0)
|
||||
res = GTK_WRAP_WORD;
|
||||
else
|
||||
res = GTK_WRAP_CHAR;
|
||||
}
|
||||
|
||||
g_free (str);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
xed_prefs_manager_set_print_wrap_mode (GtkWrapMode pwp)
|
||||
{
|
||||
const gchar *str;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
switch (pwp)
|
||||
{
|
||||
case GTK_WRAP_NONE:
|
||||
str = "GTK_WRAP_NONE";
|
||||
break;
|
||||
|
||||
case GTK_WRAP_WORD:
|
||||
str = "GTK_WRAP_WORD";
|
||||
break;
|
||||
|
||||
default: /* GTK_WRAP_CHAR */
|
||||
str = "GTK_WRAP_CHAR";
|
||||
}
|
||||
|
||||
xed_prefs_manager_set_string (GPM_PRINT_WRAP_MODE, str);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_prefs_manager_print_wrap_mode_can_set (void)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return xed_prefs_manager_key_is_writable (GPM_PRINT_WRAP_MODE);
|
||||
}
|
||||
|
||||
/* Print line numbers */
|
||||
DEFINE_INT_PREF (print_line_numbers,
|
||||
GPM_PRINT_LINE_NUMBERS)
|
||||
|
||||
/* Printing fonts */
|
||||
DEFINE_STRING_PREF (print_font_body,
|
||||
GPM_PRINT_FONT_BODY)
|
||||
|
||||
gchar *
|
||||
xed_prefs_manager_get_default_string_value (const gchar *key)
|
||||
{
|
||||
gchar *font = NULL;
|
||||
g_settings_delay (xed_prefs_manager->settings);
|
||||
g_settings_reset (xed_prefs_manager->settings, key);
|
||||
font = g_settings_get_string (xed_prefs_manager->settings, key);
|
||||
g_settings_revert (xed_prefs_manager->settings);
|
||||
return font;
|
||||
}
|
||||
|
||||
gchar *
|
||||
xed_prefs_manager_get_default_print_font_body (void)
|
||||
{
|
||||
return xed_prefs_manager_get_default_string_value (GPM_PRINT_FONT_BODY);
|
||||
}
|
||||
|
||||
DEFINE_STRING_PREF (print_font_header,
|
||||
GPM_PRINT_FONT_HEADER)
|
||||
|
||||
gchar *
|
||||
xed_prefs_manager_get_default_print_font_header (void)
|
||||
{
|
||||
return xed_prefs_manager_get_default_string_value (GPM_PRINT_FONT_HEADER);
|
||||
}
|
||||
|
||||
DEFINE_STRING_PREF (print_font_numbers,
|
||||
GPM_PRINT_FONT_NUMBERS)
|
||||
|
||||
gchar *
|
||||
xed_prefs_manager_get_default_print_font_numbers (void)
|
||||
{
|
||||
return xed_prefs_manager_get_default_string_value (GPM_PRINT_FONT_NUMBERS);
|
||||
}
|
||||
|
||||
/* Max number of files in "Recent Files" menu.
|
||||
* This is configurable only using gsettings, dconf or dconf-editor
|
||||
*/
|
||||
gint
|
||||
xed_prefs_manager_get_max_recents (void)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return xed_prefs_manager_get_int (GPM_MAX_RECENTS);
|
||||
|
||||
}
|
||||
|
||||
/* GSettings/GSList utility functions from mate-panel */
|
||||
|
||||
GSList*
|
||||
xed_prefs_manager_get_gslist (GSettings *settings, const gchar *key)
|
||||
{
|
||||
gchar **array;
|
||||
GSList *list = NULL;
|
||||
gint i;
|
||||
array = g_settings_get_strv (settings, key);
|
||||
if (array != NULL) {
|
||||
for (i = 0; array[i]; i++) {
|
||||
list = g_slist_append (list, g_strdup (array[i]));
|
||||
}
|
||||
}
|
||||
g_strfreev (array);
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
xed_prefs_manager_set_gslist (GSettings *settings, const gchar *key, GSList *list)
|
||||
{
|
||||
GArray *array;
|
||||
GSList *l;
|
||||
array = g_array_new (TRUE, TRUE, sizeof (gchar *));
|
||||
for (l = list; l; l = l->next) {
|
||||
array = g_array_append_val (array, l->data);
|
||||
}
|
||||
g_settings_set_strv (settings, key, (const gchar **) array->data);
|
||||
g_array_free (array, TRUE);
|
||||
}
|
||||
|
||||
|
||||
/* Encodings */
|
||||
|
||||
static gboolean
|
||||
data_exists (GSList *list,
|
||||
const gpointer data)
|
||||
{
|
||||
while (list != NULL)
|
||||
{
|
||||
if (list->data == data)
|
||||
return TRUE;
|
||||
|
||||
list = g_slist_next (list);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GSList *
|
||||
xed_prefs_manager_get_auto_detected_encodings (void)
|
||||
{
|
||||
GSList *strings;
|
||||
GSList *res = NULL;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
g_return_val_if_fail (xed_prefs_manager != NULL, NULL);
|
||||
g_return_val_if_fail (xed_prefs_manager->settings != NULL, NULL);
|
||||
|
||||
strings = xed_prefs_manager_get_gslist (xed_prefs_manager->settings, GPM_AUTO_DETECTED_ENCODINGS);
|
||||
|
||||
if (strings != NULL)
|
||||
{
|
||||
GSList *tmp;
|
||||
const XedEncoding *enc;
|
||||
|
||||
tmp = strings;
|
||||
|
||||
while (tmp)
|
||||
{
|
||||
const char *charset = tmp->data;
|
||||
|
||||
if (strcmp (charset, "CURRENT") == 0)
|
||||
g_get_charset (&charset);
|
||||
|
||||
g_return_val_if_fail (charset != NULL, NULL);
|
||||
enc = xed_encoding_get_from_charset (charset);
|
||||
|
||||
if (enc != NULL)
|
||||
{
|
||||
if (!data_exists (res, (gpointer)enc))
|
||||
res = g_slist_prepend (res, (gpointer)enc);
|
||||
|
||||
}
|
||||
|
||||
tmp = g_slist_next (tmp);
|
||||
}
|
||||
|
||||
g_slist_foreach (strings, (GFunc) g_free, NULL);
|
||||
g_slist_free (strings);
|
||||
|
||||
res = g_slist_reverse (res);
|
||||
}
|
||||
|
||||
xed_debug_message (DEBUG_PREFS, "Done");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GSList *
|
||||
xed_prefs_manager_get_shown_in_menu_encodings (void)
|
||||
{
|
||||
GSList *strings;
|
||||
GSList *res = NULL;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
g_return_val_if_fail (xed_prefs_manager != NULL, NULL);
|
||||
g_return_val_if_fail (xed_prefs_manager->settings != NULL, NULL);
|
||||
|
||||
strings = xed_prefs_manager_get_gslist (xed_prefs_manager->settings, GPM_SHOWN_IN_MENU_ENCODINGS);
|
||||
|
||||
if (strings != NULL)
|
||||
{
|
||||
GSList *tmp;
|
||||
const XedEncoding *enc;
|
||||
|
||||
tmp = strings;
|
||||
|
||||
while (tmp)
|
||||
{
|
||||
const char *charset = tmp->data;
|
||||
|
||||
if (strcmp (charset, "CURRENT") == 0)
|
||||
g_get_charset (&charset);
|
||||
|
||||
g_return_val_if_fail (charset != NULL, NULL);
|
||||
enc = xed_encoding_get_from_charset (charset);
|
||||
|
||||
if (enc != NULL)
|
||||
{
|
||||
if (!data_exists (res, (gpointer)enc))
|
||||
res = g_slist_prepend (res, (gpointer)enc);
|
||||
}
|
||||
|
||||
tmp = g_slist_next (tmp);
|
||||
}
|
||||
|
||||
g_slist_foreach (strings, (GFunc) g_free, NULL);
|
||||
g_slist_free (strings);
|
||||
|
||||
res = g_slist_reverse (res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
xed_prefs_manager_set_shown_in_menu_encodings (const GSList *encs)
|
||||
{
|
||||
GSList *list = NULL;
|
||||
|
||||
g_return_if_fail (xed_prefs_manager != NULL);
|
||||
g_return_if_fail (xed_prefs_manager->settings != NULL);
|
||||
g_return_if_fail (xed_prefs_manager_shown_in_menu_encodings_can_set ());
|
||||
|
||||
while (encs != NULL)
|
||||
{
|
||||
const XedEncoding *enc;
|
||||
const gchar *charset;
|
||||
|
||||
enc = (const XedEncoding *)encs->data;
|
||||
|
||||
charset = xed_encoding_get_charset (enc);
|
||||
g_return_if_fail (charset != NULL);
|
||||
|
||||
list = g_slist_prepend (list, (gpointer)charset);
|
||||
|
||||
encs = g_slist_next (encs);
|
||||
}
|
||||
|
||||
list = g_slist_reverse (list);
|
||||
|
||||
xed_prefs_manager_set_gslist (xed_prefs_manager->settings, GPM_SHOWN_IN_MENU_ENCODINGS, list);
|
||||
|
||||
g_slist_free (list);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_prefs_manager_shown_in_menu_encodings_can_set (void)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return xed_prefs_manager_key_is_writable (GPM_SHOWN_IN_MENU_ENCODINGS);
|
||||
|
||||
}
|
||||
|
||||
/* Highlight current line */
|
||||
DEFINE_BOOL_PREF (highlight_current_line,
|
||||
GPM_HIGHLIGHT_CURRENT_LINE)
|
||||
|
||||
/* Highlight matching bracket */
|
||||
DEFINE_BOOL_PREF (bracket_matching,
|
||||
GPM_BRACKET_MATCHING)
|
||||
|
||||
/* Display Right Margin */
|
||||
DEFINE_BOOL_PREF (display_right_margin,
|
||||
GPM_DISPLAY_RIGHT_MARGIN)
|
||||
|
||||
/* Right Margin Position */
|
||||
DEFINE_INT_PREF (right_margin_position,
|
||||
GPM_RIGHT_MARGIN_POSITION)
|
||||
|
||||
static GtkSourceSmartHomeEndType
|
||||
get_smart_home_end_from_string (const gchar *str)
|
||||
{
|
||||
GtkSourceSmartHomeEndType res;
|
||||
|
||||
g_return_val_if_fail (str != NULL, GTK_SOURCE_SMART_HOME_END_AFTER);
|
||||
|
||||
if (strcmp (str, "DISABLED") == 0)
|
||||
res = GTK_SOURCE_SMART_HOME_END_DISABLED;
|
||||
else if (strcmp (str, "BEFORE") == 0)
|
||||
res = GTK_SOURCE_SMART_HOME_END_BEFORE;
|
||||
else if (strcmp (str, "ALWAYS") == 0)
|
||||
res = GTK_SOURCE_SMART_HOME_END_ALWAYS;
|
||||
else
|
||||
res = GTK_SOURCE_SMART_HOME_END_AFTER;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GtkSourceSmartHomeEndType
|
||||
xed_prefs_manager_get_smart_home_end (void)
|
||||
{
|
||||
gchar *str;
|
||||
GtkSourceSmartHomeEndType res;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
str = xed_prefs_manager_get_string (GPM_SMART_HOME_END);
|
||||
|
||||
res = get_smart_home_end_from_string (str);
|
||||
|
||||
g_free (str);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
xed_prefs_manager_set_smart_home_end (GtkSourceSmartHomeEndType smart_he)
|
||||
{
|
||||
const gchar *str;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
switch (smart_he)
|
||||
{
|
||||
case GTK_SOURCE_SMART_HOME_END_DISABLED:
|
||||
str = "DISABLED";
|
||||
break;
|
||||
|
||||
case GTK_SOURCE_SMART_HOME_END_BEFORE:
|
||||
str = "BEFORE";
|
||||
break;
|
||||
|
||||
case GTK_SOURCE_SMART_HOME_END_ALWAYS:
|
||||
str = "ALWAYS";
|
||||
break;
|
||||
|
||||
default: /* GTK_SOURCE_SMART_HOME_END_AFTER */
|
||||
str = "AFTER";
|
||||
}
|
||||
|
||||
xed_prefs_manager_set_string (GPM_WRAP_MODE, str);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_prefs_manager_smart_home_end_can_set (void)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return xed_prefs_manager_key_is_writable (GPM_SMART_HOME_END);
|
||||
}
|
||||
|
||||
/* Enable syntax highlighting */
|
||||
DEFINE_BOOL_PREF (enable_syntax_highlighting,
|
||||
GPM_SYNTAX_HL_ENABLE)
|
||||
|
||||
/* Enable search highlighting */
|
||||
DEFINE_BOOL_PREF (enable_search_highlighting,
|
||||
GPM_SEARCH_HIGHLIGHTING_ENABLE)
|
||||
|
||||
/* Source style scheme */
|
||||
DEFINE_STRING_PREF (source_style_scheme,
|
||||
GPM_SOURCE_STYLE_SCHEME)
|
||||
|
||||
GSList *
|
||||
xed_prefs_manager_get_writable_vfs_schemes (void)
|
||||
{
|
||||
GSList *strings;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
g_return_val_if_fail (xed_prefs_manager != NULL, NULL);
|
||||
g_return_val_if_fail (xed_prefs_manager->settings != NULL, NULL);
|
||||
|
||||
strings = xed_prefs_manager_get_gslist (xed_prefs_manager->settings, GPM_WRITABLE_VFS_SCHEMES);
|
||||
|
||||
/* The 'file' scheme is writable by default. */
|
||||
strings = g_slist_prepend (strings, g_strdup ("file"));
|
||||
|
||||
xed_debug_message (DEBUG_PREFS, "Done");
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_prefs_manager_get_restore_cursor_position (void)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return xed_prefs_manager_get_bool (GPM_RESTORE_CURSOR_POSITION);
|
||||
}
|
||||
|
||||
/* Plugins: we just store/return a list of strings, all the magic has to
|
||||
* happen in the plugin engine */
|
||||
|
||||
GSList *
|
||||
xed_prefs_manager_get_active_plugins (void)
|
||||
{
|
||||
GSList *plugins;
|
||||
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
g_return_val_if_fail (xed_prefs_manager != NULL, NULL);
|
||||
g_return_val_if_fail (xed_prefs_manager->settings != NULL, NULL);
|
||||
|
||||
plugins = xed_prefs_manager_get_gslist (xed_prefs_manager->settings, GPM_ACTIVE_PLUGINS);
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
void
|
||||
xed_prefs_manager_set_active_plugins (const GSList *plugins)
|
||||
{
|
||||
g_return_if_fail (xed_prefs_manager != NULL);
|
||||
g_return_if_fail (xed_prefs_manager->settings != NULL);
|
||||
g_return_if_fail (xed_prefs_manager_active_plugins_can_set ());
|
||||
|
||||
xed_prefs_manager_set_gslist (xed_prefs_manager->settings, GPM_ACTIVE_PLUGINS, (GSList *) plugins);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xed_prefs_manager_active_plugins_can_set (void)
|
||||
{
|
||||
xed_debug (DEBUG_PREFS);
|
||||
|
||||
return xed_prefs_manager_key_is_writable (GPM_ACTIVE_PLUGINS);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user