Compare commits
10 Commits
master
...
khorben/re
Author | SHA1 | Date | |
---|---|---|---|
49c1d8d4e7 | |||
0f282167e1 | |||
fd59fd9733 | |||
7a789271bd | |||
15e7fd24f8 | |||
09a1e3d94e | |||
8f7432863f | |||
13765e2c51 | |||
5d27841e82 | |||
cde6cbd602 |
31
COPYING
31
COPYING
|
@ -1,3 +1,6 @@
|
|||
Copyright (c) 2013-2018, Pierre Pronchery <khorben@defora.org>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
@ -6,21 +9,17 @@ met:
|
|||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice this list of conditions and the following disclaimer in the
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the authors nor the names of the contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
../src/main.c
|
||||
../src/tab.c
|
||||
../src/terminal.c
|
||||
../src/widget.c
|
||||
../src/window.c
|
||||
|
|
44
src/common.h
Normal file
44
src/common.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Desktop Terminal */
|
||||
/* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
|
||||
|
||||
#ifndef TERMINAL_COMMON_H
|
||||
# define TERMINAL_COMMON_H
|
||||
|
||||
# include <gtk/gtk.h>
|
||||
# include <System.h>
|
||||
|
||||
|
||||
/* TerminalCommon */
|
||||
/* public */
|
||||
/* types */
|
||||
typedef struct _Terminal Terminal;
|
||||
typedef struct _TerminalTab TerminalTab;
|
||||
typedef struct _TerminalWidget TerminalWidget;
|
||||
typedef struct _TerminalWindow TerminalWindow;
|
||||
|
||||
#endif /* !TERMINAL_COMMON_H */
|
21
src/main.c
21
src/main.c
|
@ -1,5 +1,5 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2012-2016 Pierre Pronchery <khorben@defora.org> */
|
||||
/* Copyright (c) 2012-2018 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Desktop Terminal */
|
||||
/* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
|
@ -12,10 +12,6 @@
|
|||
* notice this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the authors nor the names of the contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
|
@ -42,17 +38,17 @@
|
|||
#define _(string) gettext(string)
|
||||
|
||||
/* constants */
|
||||
#ifndef PROGNAME
|
||||
# define PROGNAME "terminal"
|
||||
#ifndef PROGNAME_TERMINAL
|
||||
# define PROGNAME_TERMINAL "terminal"
|
||||
#endif
|
||||
#ifndef PREFIX
|
||||
# define PREFIX "/usr/local"
|
||||
# define PREFIX "/usr/local"
|
||||
#endif
|
||||
#ifndef DATADIR
|
||||
# define DATADIR PREFIX "/share"
|
||||
# define DATADIR PREFIX "/share"
|
||||
#endif
|
||||
#ifndef LOCALEDIR
|
||||
# define LOCALEDIR DATADIR "/locale"
|
||||
# define LOCALEDIR DATADIR "/locale"
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -89,7 +85,7 @@ static int _terminal(TerminalPrefs * prefs)
|
|||
/* error */
|
||||
static int _error(char const * message, int ret)
|
||||
{
|
||||
fputs(PROGNAME ": ", stderr);
|
||||
fputs(PROGNAME_TERMINAL ": ", stderr);
|
||||
perror(message);
|
||||
return ret;
|
||||
}
|
||||
|
@ -98,7 +94,8 @@ static int _error(char const * message, int ret)
|
|||
/* usage */
|
||||
static int _usage(void)
|
||||
{
|
||||
fprintf(stderr, _("Usage: %s [-d directory][shell]\n"), PROGNAME);
|
||||
fprintf(stderr, _("Usage: %s [-d directory][shell]\n"),
|
||||
PROGNAME_TERMINAL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,38 @@
|
|||
targets=terminal
|
||||
#cppflags=-D EMBEDDED
|
||||
cflags_force=`pkg-config --cflags libDesktop`
|
||||
cflags=-W -Wall -g -O2 -pedantic -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector
|
||||
ldflags_force=`pkg-config --libs libDesktop` -lintl
|
||||
ldflags=-pie -Wl,-z,relro -Wl,-z,now
|
||||
#for XTerm
|
||||
#cppflags_force=-DWITH_XTERM
|
||||
#cflags_force=`pkg-config --cflags libDesktop`
|
||||
#ldflags_force=`pkg-config --libs libDesktop` -lintl
|
||||
#for Gtk+ 2 (VTE)
|
||||
#cflags_force=`pkg-config --cflags libDesktop vte`
|
||||
#ldflags_force=`pkg-config --libs libDesktop vte` -lintl
|
||||
#for Gtk+ 3 (VTE)
|
||||
cflags_force=`pkg-config --cflags libDesktop vte-2.91`
|
||||
ldflags_force=`pkg-config --libs libDesktop vte-2.91` -lintl
|
||||
dist=Makefile,terminal.h
|
||||
|
||||
#targets
|
||||
[terminal]
|
||||
type=binary
|
||||
sources=terminal.c,main.c
|
||||
sources=tab.c,terminal.c,widget.c,window.c,main.c
|
||||
install=$(BINDIR)
|
||||
|
||||
#sources
|
||||
[main.c]
|
||||
depends=terminal.h,../config.h
|
||||
|
||||
[tab.c]
|
||||
depends=tab.h
|
||||
|
||||
[terminal.c]
|
||||
depends=terminal.h,../config.h
|
||||
cppflags=-D PREFIX=\"$(PREFIX)\"
|
||||
|
||||
[main.c]
|
||||
depends=terminal.h,../config.h
|
||||
[widget.c]
|
||||
depends=widget.h
|
||||
|
||||
[window.c]
|
||||
depends=window.h
|
||||
|
|
329
src/tab.c
Normal file
329
src/tab.c
Normal file
|
@ -0,0 +1,329 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Desktop Terminal */
|
||||
/* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libintl.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <sys/wait.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#ifdef WITH_XTERM
|
||||
# if GTK_CHECK_VERSION(3, 0, 0)
|
||||
# include <gtk/gtkx.h>
|
||||
# endif
|
||||
#else
|
||||
# include <vte/vte.h>
|
||||
#endif
|
||||
#include <System.h>
|
||||
#include <Desktop.h>
|
||||
#include "terminal.h"
|
||||
#include "window.h"
|
||||
#include "tab.h"
|
||||
#define _(string) gettext(string)
|
||||
|
||||
/* constants */
|
||||
#ifndef PROGNAME_TERMINAL
|
||||
# define PROGNAME_TERMINAL "terminal"
|
||||
#endif
|
||||
#ifdef WITH_XTERM
|
||||
# ifndef PROGNAME_XTERM
|
||||
# define PROGNAME_XTERM "xterm"
|
||||
# endif
|
||||
#endif
|
||||
#ifndef PREFIX
|
||||
# define PREFIX "/usr/local"
|
||||
#endif
|
||||
#ifndef BINDIR
|
||||
# define BINDIR PREFIX "/bin"
|
||||
#endif
|
||||
|
||||
|
||||
/* TerminalTab */
|
||||
/* private */
|
||||
/* types */
|
||||
struct _TerminalTab
|
||||
{
|
||||
Terminal * terminal;
|
||||
GtkWidget * widget;
|
||||
GtkWidget * label;
|
||||
GtkWidget * socket;
|
||||
GPid pid;
|
||||
guint source;
|
||||
};
|
||||
|
||||
|
||||
/* prototypes */
|
||||
/* callbacks */
|
||||
static void _terminaltab_on_child_watch(GPid pid, gint status, gpointer data);
|
||||
static void _terminaltab_on_close(gpointer data);
|
||||
static void _terminaltab_on_rename(gpointer data);
|
||||
static void _terminaltab_on_screen_changed(GtkWidget * widget,
|
||||
GdkScreen * screen, gpointer data);
|
||||
|
||||
|
||||
/* public */
|
||||
/* functions */
|
||||
/* terminaltab_new */
|
||||
TerminalTab * terminaltab_new(Terminal * terminal)
|
||||
{
|
||||
TerminalTab * tab;
|
||||
GtkWidget * widget;
|
||||
|
||||
if((tab = object_new(sizeof(*tab))) == NULL)
|
||||
return NULL;
|
||||
tab->terminal = terminal;
|
||||
tab->pid = -1;
|
||||
tab->source = 0;
|
||||
#ifdef WITH_XTERM
|
||||
tab->socket = gtk_socket_new();
|
||||
#else
|
||||
tab->socket = vte_terminal_new();
|
||||
#endif
|
||||
g_signal_connect(tab->socket, "screen-changed", G_CALLBACK(
|
||||
_terminaltab_on_screen_changed), tab);
|
||||
tab->widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
tab->label = gtk_label_new(_("xterm"));
|
||||
gtk_box_pack_start(GTK_BOX(tab->widget), tab->label, TRUE, TRUE, 0);
|
||||
widget = gtk_button_new();
|
||||
g_signal_connect_swapped(widget, "clicked", G_CALLBACK(
|
||||
_terminaltab_on_rename), tab);
|
||||
gtk_container_add(GTK_CONTAINER(widget), gtk_image_new_from_stock(
|
||||
GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
|
||||
gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NONE);
|
||||
gtk_box_pack_start(GTK_BOX(tab->widget), widget, FALSE, TRUE, 0);
|
||||
widget = gtk_button_new();
|
||||
g_signal_connect_swapped(widget, "clicked", G_CALLBACK(
|
||||
_terminaltab_on_close), tab);
|
||||
gtk_container_add(GTK_CONTAINER(widget), gtk_image_new_from_stock(
|
||||
GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU));
|
||||
gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NONE);
|
||||
gtk_box_pack_start(GTK_BOX(tab->widget), widget, FALSE, TRUE, 0);
|
||||
gtk_widget_show_all(tab->widget);
|
||||
gtk_widget_show(tab->socket);
|
||||
return tab;
|
||||
}
|
||||
|
||||
|
||||
/* terminaltab_delete */
|
||||
void terminaltab_delete(TerminalTab * tab)
|
||||
{
|
||||
if(tab->source > 0)
|
||||
g_source_remove(tab->source);
|
||||
if(tab->pid > 0)
|
||||
{
|
||||
g_spawn_close_pid(tab->pid);
|
||||
if(kill(tab->pid, SIGTERM) != 0)
|
||||
fprintf(stderr, "%s: %s: %s\n", PROGNAME_TERMINAL,
|
||||
"kill", strerror(errno));
|
||||
}
|
||||
object_delete(tab);
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
/* terminaltab_get_label */
|
||||
GtkWidget * terminaltab_get_label(TerminalTab * tab)
|
||||
{
|
||||
return tab->widget;
|
||||
}
|
||||
|
||||
|
||||
/* terminaltab_get_widget */
|
||||
GtkWidget * terminaltab_get_widget(TerminalTab * tab)
|
||||
{
|
||||
return tab->socket;
|
||||
}
|
||||
|
||||
|
||||
/* useful */
|
||||
/* terminaltab_clipboard_copy */
|
||||
void terminaltab_clipboard_copy(TerminalTab * tab)
|
||||
{
|
||||
#ifdef WITH_XTERM
|
||||
#else
|
||||
vte_terminal_copy_clipboard(VTE_TERMINAL(tab->socket));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* terminaltab_clipboard_paste */
|
||||
void terminaltab_clipboard_paste(TerminalTab * tab)
|
||||
{
|
||||
#ifdef WITH_XTERM
|
||||
#else
|
||||
vte_terminal_paste_clipboard(VTE_TERMINAL(tab->socket));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* private */
|
||||
/* functions */
|
||||
/* callbacks */
|
||||
/* terminaltab_on_child_watch */
|
||||
static void _terminaltab_on_child_watch(GPid pid, gint status, gpointer data)
|
||||
{
|
||||
TerminalTab * tab = data;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(%d, %d)\n", __func__, pid, status);
|
||||
#endif
|
||||
if(tab->pid != pid)
|
||||
return;
|
||||
if(WIFEXITED(status))
|
||||
{
|
||||
if(WEXITSTATUS(status) != 0)
|
||||
fprintf(stderr, "%s: %s%u\n", PROGNAME_TERMINAL,
|
||||
_("process exited with status "),
|
||||
WEXITSTATUS(status));
|
||||
g_spawn_close_pid(tab->pid);
|
||||
tab->pid = -1;
|
||||
terminal_tab_close(tab->terminal, tab);
|
||||
}
|
||||
else if(WIFSIGNALED(status))
|
||||
{
|
||||
fprintf(stderr, "%s: %s%u\n", PROGNAME_TERMINAL,
|
||||
_("process exited with signal "),
|
||||
WTERMSIG(status));
|
||||
g_spawn_close_pid(tab->pid);
|
||||
tab->pid = -1;
|
||||
terminal_tab_close(tab->terminal, tab);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* terminaltab_on_close */
|
||||
static void _terminaltab_on_close(gpointer data)
|
||||
{
|
||||
TerminalTab * tab = data;
|
||||
|
||||
terminal_tab_close(tab->terminal, tab);
|
||||
}
|
||||
|
||||
|
||||
/* terminaltab_on_rename */
|
||||
static void _terminaltab_on_rename(gpointer data)
|
||||
{
|
||||
TerminalTab * tab = data;
|
||||
TerminalWindow * twindow;
|
||||
GtkWidget * window;
|
||||
GtkWidget * dialog;
|
||||
GtkWidget * content;
|
||||
GtkWidget * entry;
|
||||
gchar const * p;
|
||||
|
||||
twindow = terminal_get_window(tab->terminal);
|
||||
window = terminalwindow_get_window(twindow);
|
||||
dialog = gtk_message_dialog_new(GTK_WINDOW(window),
|
||||
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_OTHER, GTK_BUTTONS_NONE,
|
||||
#if GTK_CHECK_VERSION(2, 6, 0)
|
||||
"%s", _("Rename tab"));
|
||||
# if GTK_CHECK_VERSION(2, 10, 0)
|
||||
gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(dialog),
|
||||
gtk_image_new_from_stock(GTK_STOCK_EDIT,
|
||||
GTK_ICON_SIZE_DIALOG));
|
||||
# endif
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
||||
#endif
|
||||
"%s", _("Rename this tab as:"));
|
||||
gtk_dialog_add_buttons(GTK_DIALOG(dialog),
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
|
||||
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), _("Rename tab"));
|
||||
#if GTK_CHECK_VERSION(2, 14, 0)
|
||||
content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||
#else
|
||||
content = GTK_DIALOG(dialog)->vbox;
|
||||
#endif
|
||||
entry = gtk_entry_new();
|
||||
gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
|
||||
gtk_entry_set_text(GTK_ENTRY(entry), gtk_label_get_text(
|
||||
GTK_LABEL(tab->label)));
|
||||
gtk_box_pack_start(GTK_BOX(content), entry, FALSE, TRUE, 0);
|
||||
gtk_widget_show_all(content);
|
||||
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
|
||||
{
|
||||
p = gtk_entry_get_text(GTK_ENTRY(entry));
|
||||
gtk_label_set_text(GTK_LABEL(tab->label), p);
|
||||
}
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
|
||||
/* terminaltab_on_screen_changed */
|
||||
static void _terminaltab_on_screen_changed(GtkWidget * widget,
|
||||
GdkScreen * screen, gpointer data)
|
||||
{
|
||||
TerminalTab * tab = data;
|
||||
const GSpawnFlags flags = G_SPAWN_FILE_AND_ARGV_ZERO
|
||||
| G_SPAWN_DO_NOT_REAP_CHILD;
|
||||
GError * error = NULL;
|
||||
gboolean res;
|
||||
#ifdef WITH_XTERM
|
||||
char * argv[] = { BINDIR "/" PROGNAME_XTERM, PROGNAME_XTERM,
|
||||
"-into", NULL, "-class", "Terminal", NULL, NULL, NULL };
|
||||
char buf[32];
|
||||
|
||||
if(screen != NULL)
|
||||
return;
|
||||
/* launch xterm */
|
||||
snprintf(buf, sizeof(buf), "%lu", gtk_socket_get_id(
|
||||
GTK_SOCKET(widget)));
|
||||
argv[3] = buf;
|
||||
if(terminal_is_login(tab->terminal))
|
||||
{
|
||||
argv[6] = "-ls";
|
||||
argv[7] = terminal_get_shell(tab->terminal);
|
||||
}
|
||||
else
|
||||
argv[6] = terminal_get_shell(tab->terminal);
|
||||
res = g_spawn_async(terminal_get_directory(tab->terminal), argv, NULL,
|
||||
flags, NULL, NULL, &tab->pid, &error);
|
||||
#else
|
||||
char * argv[] = { NULL, NULL, NULL };
|
||||
|
||||
if((argv[0] = vte_get_user_shell()) == NULL)
|
||||
argv[0] = "/bin/sh";
|
||||
argv[1] = g_path_get_basename(argv[0]);
|
||||
res = vte_terminal_spawn_sync(VTE_TERMINAL(tab->socket),
|
||||
VTE_PTY_DEFAULT, NULL, argv, NULL, flags, NULL, NULL,
|
||||
&tab->pid, NULL, &error);
|
||||
g_free(argv[1]);
|
||||
#endif
|
||||
if(res == FALSE)
|
||||
{
|
||||
fprintf(stderr, "%s: %s: %s\n", PROGNAME_TERMINAL, argv[0],
|
||||
error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
tab->source = g_child_watch_add(tab->pid, _terminaltab_on_child_watch,
|
||||
tab);
|
||||
}
|
49
src/tab.h
Normal file
49
src/tab.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Desktop Terminal */
|
||||
/* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
|
||||
|
||||
#ifndef TERMINAL_TAB_H
|
||||
# define TERMINAL_TAB_H
|
||||
|
||||
# include "common.h"
|
||||
|
||||
|
||||
/* TerminalTab */
|
||||
/* public */
|
||||
/* functions */
|
||||
TerminalTab * terminaltab_new(Terminal * terminal);
|
||||
void terminaltab_delete(TerminalTab * tab);
|
||||
|
||||
/* accessors */
|
||||
GtkWidget * terminaltab_get_label(TerminalTab * tab);
|
||||
GtkWidget * terminaltab_get_widget(TerminalTab * tab);
|
||||
|
||||
/* useful */
|
||||
void terminaltab_clipboard_copy(TerminalTab * tab);
|
||||
void terminaltab_clipboard_paste(TerminalTab * tab);
|
||||
|
||||
#endif /* !TERMINAL_TAB_H */
|
734
src/terminal.c
734
src/terminal.c
|
@ -1,203 +1,68 @@
|
|||
/* $Id$ */
|
||||
static char const _copyright[] =
|
||||
"Copyright © 2012-2018 Pierre Pronchery <khorben@defora.org>";
|
||||
/* Copyright (c) 2012-2018 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Desktop Terminal */
|
||||
static char const _license[] =
|
||||
"Redistribution and use in source and binary forms, with or without\n"
|
||||
"modification, are permitted provided that the following conditions are\n"
|
||||
"met:\n"
|
||||
"\n"
|
||||
"1. Redistributions of source code must retain the above copyright\n"
|
||||
" notice, this list of conditions and the following disclaimer.\n"
|
||||
"\n"
|
||||
"2. Redistributions in binary form must reproduce the above copyright\n"
|
||||
" notice this list of conditions and the following disclaimer in the\n"
|
||||
" documentation and/or other materials provided with the distribution.\n"
|
||||
"\n"
|
||||
"3. Neither the name of the authors nor the names of the contributors may\n"
|
||||
" be used to endorse or promote products derived from this software\n"
|
||||
" without specific prior written permission.\n"
|
||||
"\n"
|
||||
"THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS \"AS IS\" AND\n"
|
||||
"ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
|
||||
"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n"
|
||||
"PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS\n"
|
||||
"BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
|
||||
"CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
|
||||
"SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
|
||||
"INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
|
||||
"CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
|
||||
"ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n"
|
||||
"THE POSSIBILITY OF SUCH DAMAGE.";
|
||||
/* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
/* TODO:
|
||||
* - figure how to handle X resources */
|
||||
|
||||
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
# include <gtk/gtkx.h>
|
||||
#endif
|
||||
#include <System.h>
|
||||
#include <Desktop.h>
|
||||
#include "tab.h"
|
||||
#include "widget.h"
|
||||
#include "window.h"
|
||||
#include "terminal.h"
|
||||
#include "../config.h"
|
||||
#define _(string) gettext(string)
|
||||
#define N_(string) (string)
|
||||
|
||||
/* constants */
|
||||
#ifndef PROGNAME
|
||||
# define PROGNAME "terminal"
|
||||
#ifndef PROGNAME_TERMINAL
|
||||
# define PROGNAME_TERMINAL "terminal"
|
||||
#endif
|
||||
#ifndef PREFIX
|
||||
# define PREFIX "/usr/local"
|
||||
# define PREFIX "/usr/local"
|
||||
#endif
|
||||
#ifndef BINDIR
|
||||
# define BINDIR PREFIX "/bin"
|
||||
# define BINDIR PREFIX "/bin"
|
||||
#endif
|
||||
|
||||
|
||||
/* Terminal */
|
||||
/* private */
|
||||
/* types */
|
||||
typedef struct _TerminalTab TerminalTab;
|
||||
|
||||
struct _Terminal
|
||||
{
|
||||
char * shell;
|
||||
char * directory;
|
||||
String * shell;
|
||||
String * directory;
|
||||
unsigned int login;
|
||||
|
||||
/* internal */
|
||||
TerminalTab ** tabs;
|
||||
size_t tabs_cnt;
|
||||
|
||||
/* widgets */
|
||||
GtkWidget * window;
|
||||
gboolean fullscreen;
|
||||
#ifndef EMBEDDED
|
||||
GtkWidget * menubar;
|
||||
#endif
|
||||
GtkToolItem * tb_fullscreen;
|
||||
GtkWidget * notebook;
|
||||
};
|
||||
|
||||
struct _TerminalTab
|
||||
{
|
||||
Terminal * terminal;
|
||||
GtkWidget * widget;
|
||||
GtkWidget * label;
|
||||
GtkWidget * socket;
|
||||
GPid pid;
|
||||
guint source;
|
||||
};
|
||||
|
||||
|
||||
/* constants */
|
||||
#ifndef EMBEDDED
|
||||
static char const * _authors[] =
|
||||
{
|
||||
"Pierre Pronchery <khorben@defora.org>",
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/* prototypes */
|
||||
/* useful */
|
||||
static int _terminal_open_tab(Terminal * terminal);
|
||||
static int _terminal_open_window(Terminal * terminal);
|
||||
static void _terminal_close_tab(Terminal * terminal, unsigned int i);
|
||||
static void _terminal_close_all(Terminal * terminal);
|
||||
|
||||
/* callbacks */
|
||||
static void _terminal_on_child_watch(GPid pid, gint status, gpointer data);
|
||||
static void _terminal_on_close(gpointer data);
|
||||
static gboolean _terminal_on_closex(gpointer data);
|
||||
static void _terminal_on_fullscreen(gpointer data);
|
||||
static void _terminal_on_new_tab(gpointer data);
|
||||
static void _terminal_on_new_window(gpointer data);
|
||||
static void _terminal_on_tab_close(gpointer data);
|
||||
static void _terminal_on_tab_rename(gpointer data);
|
||||
|
||||
#ifndef EMBEDDED
|
||||
static void _terminal_on_file_close(gpointer data);
|
||||
static void _terminal_on_file_close_all(gpointer data);
|
||||
static void _terminal_on_file_new_tab(gpointer data);
|
||||
static void _terminal_on_file_new_window(gpointer data);
|
||||
static void _terminal_on_view_fullscreen(gpointer data);
|
||||
static void _terminal_on_help_about(gpointer data);
|
||||
static void _terminal_on_help_contents(gpointer data);
|
||||
#endif
|
||||
|
||||
|
||||
/* constants */
|
||||
#ifndef EMBEDDED
|
||||
/* menubar */
|
||||
static const DesktopMenu _terminal_file_menu[] =
|
||||
{
|
||||
{ N_("New _tab"), G_CALLBACK(_terminal_on_file_new_tab), "tab-new",
|
||||
GDK_CONTROL_MASK, GDK_KEY_T },
|
||||
{ N_("_New window"), G_CALLBACK(_terminal_on_file_new_window),
|
||||
"window-new", GDK_CONTROL_MASK, GDK_KEY_N },
|
||||
{ "", NULL, NULL, 0, 0 },
|
||||
{ N_("_Close"), G_CALLBACK(_terminal_on_file_close), GTK_STOCK_CLOSE,
|
||||
GDK_CONTROL_MASK, GDK_KEY_W },
|
||||
{ N_("Close all tabs"), G_CALLBACK(_terminal_on_file_close_all), NULL,
|
||||
GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_KEY_W },
|
||||
{ NULL, NULL, NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static const DesktopMenu _terminal_view_menu[] =
|
||||
{
|
||||
{ N_("_Fullscreen"), G_CALLBACK(_terminal_on_view_fullscreen),
|
||||
# if GTK_CHECK_VERSION(2, 8, 0)
|
||||
GTK_STOCK_FULLSCREEN,
|
||||
# else
|
||||
NULL,
|
||||
# endif
|
||||
0, GDK_KEY_F11 },
|
||||
{ NULL, NULL, NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static const DesktopMenu _terminal_help_menu[] =
|
||||
{
|
||||
{ N_("_Contents"), G_CALLBACK(_terminal_on_help_contents),
|
||||
"help-contents", 0, GDK_KEY_F1 },
|
||||
#if GTK_CHECK_VERSION(2, 6, 0)
|
||||
{ N_("_About"), G_CALLBACK(_terminal_on_help_about), GTK_STOCK_ABOUT, 0,
|
||||
0 },
|
||||
#else
|
||||
{ N_("_About"), G_CALLBACK(_terminal_on_help_about), NULL, 0, 0 },
|
||||
#endif
|
||||
{ NULL, NULL, NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static const DesktopMenubar _terminal_menubar[] =
|
||||
{
|
||||
{ N_("_File"), _terminal_file_menu },
|
||||
{ N_("_View"), _terminal_view_menu },
|
||||
{ N_("_Help"), _terminal_help_menu },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
#endif
|
||||
|
||||
static DesktopToolbar _terminal_toolbar[] =
|
||||
{
|
||||
{ N_("New tab"), G_CALLBACK(_terminal_on_new_tab), "tab-new", 0, 0,
|
||||
NULL },
|
||||
{ N_("New window"), G_CALLBACK(_terminal_on_new_window), "window-new",
|
||||
0, 0, NULL },
|
||||
{ "", NULL, NULL, 0, 0, NULL },
|
||||
{ NULL, NULL, NULL, 0, 0, NULL }
|
||||
TerminalWindow * window;
|
||||
};
|
||||
|
||||
|
||||
|
@ -207,10 +72,6 @@ static DesktopToolbar _terminal_toolbar[] =
|
|||
Terminal * terminal_new(TerminalPrefs * prefs)
|
||||
{
|
||||
Terminal * terminal;
|
||||
GtkAccelGroup * group;
|
||||
GtkWidget * vbox;
|
||||
GtkWidget * widget;
|
||||
GtkToolItem * toolitem;
|
||||
|
||||
if((terminal = object_new(sizeof(*terminal))) == NULL)
|
||||
return NULL;
|
||||
|
@ -219,61 +80,18 @@ Terminal * terminal_new(TerminalPrefs * prefs)
|
|||
terminal->directory = (prefs != NULL && prefs->directory != NULL)
|
||||
? string_new(prefs->directory) : NULL;
|
||||
terminal->login = (prefs != NULL) ? prefs->login : 0;
|
||||
terminal->tabs = NULL;
|
||||
terminal->tabs_cnt = 0;
|
||||
terminal->window = NULL;
|
||||
terminal->fullscreen = FALSE;
|
||||
/* check for errors */
|
||||
if((prefs != NULL && prefs->shell != NULL && terminal->shell == NULL)
|
||||
|| (prefs != NULL && prefs->directory != NULL
|
||||
&& terminal->directory == NULL))
|
||||
&& terminal->directory == NULL)
|
||||
|| (terminal->window = terminalwindow_new(terminal))
|
||||
== NULL)
|
||||
{
|
||||
terminal_delete(terminal);
|
||||
return NULL;
|
||||
}
|
||||
/* widgets */
|
||||
group = gtk_accel_group_new();
|
||||
terminal->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_add_accel_group(GTK_WINDOW(terminal->window), group);
|
||||
g_object_unref(group);
|
||||
gtk_window_set_default_size(GTK_WINDOW(terminal->window), 600, 400);
|
||||
#if GTK_CHECK_VERSION(2, 6, 0)
|
||||
gtk_window_set_icon_name(GTK_WINDOW(terminal->window), "terminal");
|
||||
#endif
|
||||
gtk_window_set_title(GTK_WINDOW(terminal->window), _("Terminal"));
|
||||
g_signal_connect_swapped(terminal->window, "delete-event", G_CALLBACK(
|
||||
_terminal_on_closex), terminal);
|
||||
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
#ifndef EMBEDDED
|
||||
/* menubar */
|
||||
terminal->menubar = desktop_menubar_create(_terminal_menubar, terminal,
|
||||
group);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), terminal->menubar, FALSE, TRUE, 0);
|
||||
#endif
|
||||
/* toolbar */
|
||||
widget = desktop_toolbar_create(_terminal_toolbar, terminal, group);
|
||||
#if GTK_CHECK_VERSION(2, 8, 0)
|
||||
toolitem = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_FULLSCREEN);
|
||||
#else
|
||||
toolitem = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_ZOOM_FIT);
|
||||
#endif
|
||||
terminal->tb_fullscreen = toolitem;
|
||||
g_signal_connect_swapped(G_OBJECT(toolitem), "toggled", G_CALLBACK(
|
||||
_terminal_on_fullscreen), terminal);
|
||||
gtk_toolbar_insert(GTK_TOOLBAR(widget), toolitem, -1);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
|
||||
/* view */
|
||||
terminal->notebook = gtk_notebook_new();
|
||||
gtk_notebook_set_scrollable(GTK_NOTEBOOK(terminal->notebook), TRUE);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), terminal->notebook, TRUE, TRUE, 0);
|
||||
gtk_container_add(GTK_CONTAINER(terminal->window), vbox);
|
||||
gtk_widget_show_all(vbox);
|
||||
if(_terminal_open_tab(terminal) != 0)
|
||||
{
|
||||
terminal_delete(terminal);
|
||||
return NULL;
|
||||
}
|
||||
gtk_widget_show(terminal->window);
|
||||
terminal_tab_open(terminal);
|
||||
return terminal;
|
||||
}
|
||||
|
||||
|
@ -281,20 +99,8 @@ Terminal * terminal_new(TerminalPrefs * prefs)
|
|||
/* terminal_delete */
|
||||
void terminal_delete(Terminal * terminal)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < terminal->tabs_cnt; i++)
|
||||
{
|
||||
if(terminal->tabs[i]->source > 0)
|
||||
g_source_remove(terminal->tabs[i]->source);
|
||||
if(terminal->tabs[i]->pid > 0)
|
||||
g_spawn_close_pid(terminal->tabs[i]->pid);
|
||||
free(terminal->tabs[i]);
|
||||
}
|
||||
/* FIXME also take care of the sub-processes */
|
||||
if(terminal->window != NULL)
|
||||
gtk_widget_destroy(terminal->window);
|
||||
free(terminal->tabs);
|
||||
terminalwindow_delete(terminal->window);
|
||||
string_delete(terminal->directory);
|
||||
string_delete(terminal->shell);
|
||||
object_delete(terminal);
|
||||
|
@ -302,435 +108,81 @@ void terminal_delete(Terminal * terminal)
|
|||
|
||||
|
||||
/* accessors */
|
||||
/* terminal_set_fullscreen */
|
||||
void terminal_set_fullscreen(Terminal * terminal, gboolean fullscreen)
|
||||
/* terminal_get_directory */
|
||||
char const * terminal_get_directory(Terminal * terminal)
|
||||
{
|
||||
if(fullscreen)
|
||||
{
|
||||
#ifndef EMBEDDED
|
||||
gtk_widget_hide(terminal->menubar);
|
||||
#endif
|
||||
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(
|
||||
terminal->tb_fullscreen), TRUE);
|
||||
gtk_window_fullscreen(GTK_WINDOW(terminal->window));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(
|
||||
terminal->tb_fullscreen), FALSE);
|
||||
gtk_window_unfullscreen(GTK_WINDOW(terminal->window));
|
||||
#ifndef EMBEDDED
|
||||
gtk_widget_show(terminal->menubar);
|
||||
#endif
|
||||
}
|
||||
terminal->fullscreen = fullscreen;
|
||||
return terminal->directory;
|
||||
}
|
||||
|
||||
|
||||
/* terminal_get_shell */
|
||||
char const * terminal_get_shell(Terminal * terminal)
|
||||
{
|
||||
return terminal->shell;
|
||||
}
|
||||
|
||||
|
||||
/* terminal_get_window */
|
||||
TerminalWindow * terminal_get_window(Terminal * terminal)
|
||||
{
|
||||
return terminal->window;
|
||||
}
|
||||
|
||||
|
||||
/* terminal_is_login */
|
||||
gboolean terminal_is_login(Terminal * terminal)
|
||||
{
|
||||
return (terminal->login > 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* private */
|
||||
/* functions */
|
||||
/* useful */
|
||||
/* terminal_open_tab */
|
||||
static int _terminal_open_tab(Terminal * terminal)
|
||||
/* terminal_tab_close */
|
||||
void terminal_tab_close(Terminal * terminal, TerminalTab * tab)
|
||||
{
|
||||
TerminalTab ** p;
|
||||
TerminalTab * tab;
|
||||
GtkWidget * widget;
|
||||
char * argv[] = { BINDIR "/xterm", "xterm", "-into", NULL,
|
||||
"-class", "Terminal", NULL, NULL, NULL };
|
||||
char buf[32];
|
||||
GSpawnFlags flags = G_SPAWN_FILE_AND_ARGV_ZERO
|
||||
| G_SPAWN_DO_NOT_REAP_CHILD;
|
||||
GError * error = NULL;
|
||||
TerminalWidget * widget;
|
||||
|
||||
if((p = realloc(terminal->tabs, sizeof(*p) * (terminal->tabs_cnt + 1)))
|
||||
== NULL)
|
||||
return -1;
|
||||
terminal->tabs = p;
|
||||
if((tab = malloc(sizeof(*tab))) == NULL)
|
||||
return -1;
|
||||
terminal->tabs[terminal->tabs_cnt++] = tab;
|
||||
/* create the tab */
|
||||
tab->terminal = terminal;
|
||||
tab->socket = gtk_socket_new();
|
||||
tab->widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
tab->label = gtk_label_new(_("xterm"));
|
||||
gtk_box_pack_start(GTK_BOX(tab->widget), tab->label, TRUE, TRUE, 0);
|
||||
widget = gtk_button_new();
|
||||
g_signal_connect_swapped(widget, "clicked", G_CALLBACK(
|
||||
_terminal_on_tab_rename), tab);
|
||||
gtk_container_add(GTK_CONTAINER(widget), gtk_image_new_from_stock(
|
||||
GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
|
||||
gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NONE);
|
||||
gtk_box_pack_start(GTK_BOX(tab->widget), widget, FALSE, TRUE, 0);
|
||||
widget = gtk_button_new();
|
||||
g_signal_connect_swapped(widget, "clicked", G_CALLBACK(
|
||||
_terminal_on_tab_close), tab);
|
||||
gtk_container_add(GTK_CONTAINER(widget), gtk_image_new_from_stock(
|
||||
GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU));
|
||||
gtk_button_set_relief(GTK_BUTTON(widget), GTK_RELIEF_NONE);
|
||||
gtk_box_pack_start(GTK_BOX(tab->widget), widget, FALSE, TRUE, 0);
|
||||
gtk_widget_show_all(tab->widget);
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(terminal->notebook), tab->socket,
|
||||
tab->widget);
|
||||
#if GTK_CHECK_VERSION(2, 10, 0)
|
||||
gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(terminal->notebook),
|
||||
tab->socket, TRUE);
|
||||
#endif
|
||||
/* launch xterm */
|
||||
snprintf(buf, sizeof(buf), "%lu", gtk_socket_get_id(
|
||||
GTK_SOCKET(tab->socket)));
|
||||
argv[3] = buf;
|
||||
if(terminal->login)
|
||||
{
|
||||
argv[6] = "-ls";
|
||||
argv[7] = terminal->shell;
|
||||
}
|
||||
else
|
||||
argv[6] = terminal->shell;
|
||||
if(g_spawn_async(terminal->directory, argv, NULL, flags, NULL, NULL,
|
||||
&tab->pid, &error) == FALSE)
|
||||
{
|
||||
fprintf(stderr, "%s: %s: %s\n", PROGNAME, argv[1],
|
||||
error->message);
|
||||
g_error_free(error);
|
||||
return -1;
|
||||
}
|
||||
tab->source = g_child_watch_add(tab->pid, _terminal_on_child_watch,
|
||||
terminal);
|
||||
gtk_widget_show(tab->socket);
|
||||
return 0;
|
||||
widget = terminalwindow_get_widget(terminal->window);
|
||||
terminalwidget_tab_close(widget, tab);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_open_window */
|
||||
static int _terminal_open_window(Terminal * terminal)
|
||||
/* terminal_tab_close_all */
|
||||
void terminal_tab_close_all(Terminal * terminal)
|
||||
{
|
||||
char * argv[] = { BINDIR "/" PROGNAME, PROGNAME, NULL };
|
||||
TerminalWidget * widget;
|
||||
|
||||
widget = terminalwindow_get_widget(terminal->window);
|
||||
terminalwidget_tab_close_all(widget);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_tab_open */
|
||||
TerminalTab * terminal_tab_open(Terminal * terminal)
|
||||
{
|
||||
TerminalWidget * widget;
|
||||
|
||||
widget = terminalwindow_get_widget(terminal->window);
|
||||
return terminalwidget_tab_open(widget);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_window_open */
|
||||
int terminal_window_open(Terminal * terminal)
|
||||
{
|
||||
char * argv[] = { BINDIR "/" PROGNAME_TERMINAL, PROGNAME_TERMINAL,
|
||||
NULL };
|
||||
GSpawnFlags flags = G_SPAWN_FILE_AND_ARGV_ZERO;
|
||||
GError * error = NULL;
|
||||
|
||||
if(g_spawn_async(NULL, argv, NULL, flags, NULL, NULL, NULL, &error)
|
||||
== FALSE)
|
||||
{
|
||||
fprintf(stderr, "%s: %s: %s\n", PROGNAME, argv[0],
|
||||
/* XXX use the current window or a dialog box */
|
||||
fprintf(stderr, "%s: %s: %s\n", PROGNAME_TERMINAL, argv[0],
|
||||
error->message);
|
||||
g_error_free(error);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* terminal_close_all */
|
||||
static void _terminal_close_all(Terminal * terminal)
|
||||
{
|
||||
GPid * pid;
|
||||
size_t i;
|
||||
size_t cnt;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s()\n", __func__);
|
||||
#endif
|
||||
gtk_widget_hide(terminal->window);
|
||||
/* work on a copy */
|
||||
if((pid = malloc(sizeof(*pid) * terminal->tabs_cnt)) == NULL)
|
||||
{
|
||||
gtk_main_quit();
|
||||
return;
|
||||
}
|
||||
cnt = terminal->tabs_cnt;
|
||||
for(i = 0; i < cnt; i++)
|
||||
{
|
||||
pid[i] = terminal->tabs[i]->pid;
|
||||
g_spawn_close_pid(terminal->tabs[i]->pid);
|
||||
terminal->tabs[i]->pid = -1;
|
||||
}
|
||||
/* kill the remaining tabs */
|
||||
for(i = 0; i < cnt; i++)
|
||||
if(kill(pid[i], SIGTERM) != 0)
|
||||
fprintf(stderr, "%s: %s: %s\n", PROGNAME, "kill",
|
||||
strerror(errno));
|
||||
free(pid);
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
|
||||
/* terminal_close_tab */
|
||||
static void _terminal_close_tab(Terminal * terminal, unsigned int i)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(%u)\n", __func__, i);
|
||||
#endif
|
||||
if(terminal->tabs[i]->source > 0)
|
||||
g_source_remove(terminal->tabs[i]->source);
|
||||
if(terminal->tabs[i]->pid >= 0)
|
||||
{
|
||||
g_spawn_close_pid(terminal->tabs[i]->pid);
|
||||
if(kill(terminal->tabs[i]->pid, SIGTERM) != 0)
|
||||
fprintf(stderr, "%s: %s: %s\n", PROGNAME, "kill",
|
||||
strerror(errno));
|
||||
}
|
||||
free(terminal->tabs[i]);
|
||||
gtk_notebook_remove_page(GTK_NOTEBOOK(terminal->notebook), i);
|
||||
memmove(&terminal->tabs[i], &terminal->tabs[i + 1],
|
||||
(terminal->tabs_cnt - (i + 1))
|
||||
* sizeof(*terminal->tabs));
|
||||
if(--terminal->tabs_cnt == 0)
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
|
||||
/* callbacks */
|
||||
/* terminal_on_child_watch */
|
||||
static void _terminal_on_child_watch(GPid pid, gint status, gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
size_t i;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(%d, %d)\n", __func__, pid, status);
|
||||
#endif
|
||||
for(i = 0; i < terminal->tabs_cnt; i++)
|
||||
if(terminal->tabs[i]->pid == pid)
|
||||
break;
|
||||
if(i >= terminal->tabs_cnt)
|
||||
return;
|
||||
if(WIFEXITED(status))
|
||||
{
|
||||
if(WEXITSTATUS(status) != 0)
|
||||
fprintf(stderr, "%s: %s%u\n", PROGNAME,
|
||||
_("xterm exited with status "),
|
||||
WEXITSTATUS(status));
|
||||
g_spawn_close_pid(terminal->tabs[i]->pid);
|
||||
terminal->tabs[i]->pid = -1;
|
||||
_terminal_close_tab(terminal, i);
|
||||
}
|
||||
else if(WIFSIGNALED(status))
|
||||
{
|
||||
fprintf(stderr, "%s: %s%u\n", PROGNAME,
|
||||
_("xterm exited with signal "),
|
||||
WTERMSIG(status));
|
||||
g_spawn_close_pid(terminal->tabs[i]->pid);
|
||||
terminal->tabs[i]->pid = -1;
|
||||
_terminal_close_tab(terminal, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_close */
|
||||
static void _terminal_on_close(gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
int i;
|
||||
|
||||
i = gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook));
|
||||
if(i < 0)
|
||||
return;
|
||||
_terminal_close_tab(terminal, i);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_closex */
|
||||
static gboolean _on_closex_confirm(Terminal * terminal);
|
||||
|
||||
static gboolean _terminal_on_closex(gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
|
||||
if(terminal->tabs_cnt > 1 && _on_closex_confirm(terminal) != TRUE)
|
||||
return TRUE;
|
||||
_terminal_close_all(terminal);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean _on_closex_confirm(Terminal * terminal)
|
||||
{
|
||||
GtkWidget * dialog;
|
||||
gboolean res;
|
||||
|
||||
dialog = gtk_message_dialog_new(GTK_WINDOW(terminal->window),
|
||||
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
|
||||
#if GTK_CHECK_VERSION(2, 6, 0)
|
||||
"%s", _("Question"));
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
||||
#endif
|
||||
"%s", _("There are multiple tabs opened.\n"
|
||||
"Do you really want to close every tab"
|
||||
" opened in this window?"));
|
||||
gtk_dialog_add_buttons(GTK_DIALOG(dialog),
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), _("Question"));
|
||||
res = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
return (res == GTK_RESPONSE_CLOSE) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_fullscreen */
|
||||
static void _terminal_on_fullscreen(gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
|
||||
terminal_set_fullscreen(terminal, terminal->fullscreen ? FALSE : TRUE);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_new_tab */
|
||||
static void _terminal_on_new_tab(gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
|
||||
_terminal_open_tab(terminal);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_new_window */
|
||||
static void _terminal_on_new_window(gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
|
||||
_terminal_open_window(terminal);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_tab_close */
|
||||
static void _terminal_on_tab_close(gpointer data)
|
||||
{
|
||||
TerminalTab * tab = data;
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < tab->terminal->tabs_cnt; i++)
|
||||
if(tab->terminal->tabs[i]->widget == tab->widget)
|
||||
break;
|
||||
if(i >= tab->terminal->tabs_cnt)
|
||||
/* should not happen */
|
||||
return;
|
||||
_terminal_close_tab(tab->terminal, i);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_tab_rename */
|
||||
static void _terminal_on_tab_rename(gpointer data)
|
||||
{
|
||||
TerminalTab * tab = data;
|
||||
GtkWidget * dialog;
|
||||
GtkWidget * content;
|
||||
GtkWidget * entry;
|
||||
gchar const * p;
|
||||
|
||||
dialog = gtk_message_dialog_new(GTK_WINDOW(tab->terminal->window),
|
||||
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_OTHER, GTK_BUTTONS_NONE,
|
||||
#if GTK_CHECK_VERSION(2, 6, 0)
|
||||
"%s", _("Rename tab"));
|
||||
# if GTK_CHECK_VERSION(2, 10, 0)
|
||||
gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(dialog),
|
||||
gtk_image_new_from_stock(GTK_STOCK_EDIT,
|
||||
GTK_ICON_SIZE_DIALOG));
|
||||
# endif
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
||||
#endif
|
||||
"%s", _("Rename this tab as:"));
|
||||
gtk_dialog_add_buttons(GTK_DIALOG(dialog),
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
|
||||
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), _("Rename tab"));
|
||||
#if GTK_CHECK_VERSION(2, 14, 0)
|
||||
content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||
#else
|
||||
content = GTK_DIALOG(dialog)->vbox;
|
||||
#endif
|
||||
entry = gtk_entry_new();
|
||||
gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
|
||||
gtk_entry_set_text(GTK_ENTRY(entry), gtk_label_get_text(
|
||||
GTK_LABEL(tab->label)));
|
||||
gtk_box_pack_start(GTK_BOX(content), entry, FALSE, TRUE, 0);
|
||||
gtk_widget_show_all(content);
|
||||
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
|
||||
{
|
||||
p = gtk_entry_get_text(GTK_ENTRY(entry));
|
||||
gtk_label_set_text(GTK_LABEL(tab->label), p);
|
||||
}
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
|
||||
#ifndef EMBEDDED
|
||||
/* terminal_on_file_close */
|
||||
static void _terminal_on_file_close(gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
|
||||
_terminal_on_close(terminal);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_file_close_all */
|
||||
static void _terminal_on_file_close_all(gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
|
||||
_terminal_close_all(terminal);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_file_new_tab */
|
||||
static void _terminal_on_file_new_tab(gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
|
||||
_terminal_open_tab(terminal);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_file_new_window */
|
||||
static void _terminal_on_file_new_window(gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
|
||||
_terminal_open_window(terminal);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_help_about */
|
||||
static void _terminal_on_help_about(gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
GtkWidget * dialog;
|
||||
|
||||
dialog = desktop_about_dialog_new();
|
||||
gtk_window_set_transient_for(GTK_WINDOW(dialog),
|
||||
GTK_WINDOW(terminal->window));
|
||||
desktop_about_dialog_set_authors(dialog, _authors);
|
||||
desktop_about_dialog_set_comments(dialog,
|
||||
_("Terminal for the DeforaOS desktop"));
|
||||
desktop_about_dialog_set_copyright(dialog, _copyright);
|
||||
desktop_about_dialog_set_license(dialog, _license);
|
||||
desktop_about_dialog_set_logo_icon_name(dialog, "terminal");
|
||||
desktop_about_dialog_set_program_name(dialog, PACKAGE);
|
||||
desktop_about_dialog_set_version(dialog, VERSION);
|
||||
desktop_about_dialog_set_website(dialog, "http://www.defora.org/");
|
||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_help_contents */
|
||||
static void _terminal_on_help_contents(gpointer data)
|
||||
{
|
||||
desktop_help_contents(PACKAGE, PROGNAME);
|
||||
}
|
||||
|
||||
|
||||
/* terminal_on_view_fullscreen */
|
||||
static void _terminal_on_view_fullscreen(gpointer data)
|
||||
{
|
||||
Terminal * terminal = data;
|
||||
|
||||
_terminal_on_fullscreen(terminal);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2012-2016 Pierre Pronchery <khorben@defora.org> */
|
||||
/* Copyright (c) 2012-2018 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Desktop Terminal */
|
||||
/* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
|
@ -12,10 +12,6 @@
|
|||
* notice this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the authors nor the names of the contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
|
@ -33,27 +29,36 @@
|
|||
#ifndef TERMINAL_TERMINAL_H
|
||||
# define TERMINAL_TERMINAL_H
|
||||
|
||||
# include "common.h"
|
||||
|
||||
|
||||
/* Terminal */
|
||||
/* public */
|
||||
/* types */
|
||||
typedef struct _TerminalPrefs
|
||||
{
|
||||
char const * shell;
|
||||
char const * directory;
|
||||
String const * shell;
|
||||
String const * directory;
|
||||
unsigned int login;
|
||||
} TerminalPrefs;
|
||||
|
||||
typedef struct _Terminal Terminal;
|
||||
|
||||
|
||||
/* functions */
|
||||
/* essential */
|
||||
Terminal * terminal_new(TerminalPrefs * prefs);
|
||||
void terminal_delete(Terminal * terminal);
|
||||
|
||||
|
||||
/* accessors */
|
||||
void terminal_set_fullscreen(Terminal * terminal, gboolean fullscreen);
|
||||
String const * terminal_get_directory(Terminal * terminal);
|
||||
String const * terminal_get_shell(Terminal * terminal);
|
||||
TerminalWindow * terminal_get_window(Terminal * terminal);
|
||||
gboolean terminal_is_login(Terminal * terminal);
|
||||
|
||||
/* useful */
|
||||
void terminal_tab_close(Terminal * terminal, TerminalTab * tab);
|
||||
void terminal_tab_close_all(Terminal * terminal);
|
||||
TerminalTab * terminal_tab_open(Terminal * terminal);
|
||||
|
||||
int terminal_window_open(Terminal * terminal);
|
||||
|
||||
#endif /* !TERMINAL_TERMINAL_H */
|
||||
|
|
581
src/widget.c
Normal file
581
src/widget.c
Normal file
|
@ -0,0 +1,581 @@
|
|||
/* $Id$ */
|
||||
static char const _copyright[] =
|
||||
"Copyright © 2012-2018 Pierre Pronchery <khorben@defora.org>";
|
||||
/* This file is part of DeforaOS Desktop Terminal */
|
||||
static char const _license[] =
|
||||
"Redistribution and use in source and binary forms, with or without\n"
|
||||
"modification, are permitted provided that the following conditions are\n"
|
||||
"met:\n"
|
||||
"\n"
|
||||
"1. Redistributions of source code must retain the above copyright\n"
|
||||
" notice, this list of conditions and the following disclaimer.\n"
|
||||
"\n"
|
||||
"2. Redistributions in binary form must reproduce the above copyright\n"
|
||||
" notice this list of conditions and the following disclaimer in the\n"
|
||||
" documentation and/or other materials provided with the distribution.\n"
|
||||
"\n"
|
||||
"THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS \"AS IS\" AND\n"
|
||||
"ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
|
||||
"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n"
|
||||
"PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS\n"
|
||||
"BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
|
||||
"CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
|
||||
"SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
|
||||
"INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
|
||||
"CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
|
||||
"ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n"
|
||||
"THE POSSIBILITY OF SUCH DAMAGE.";
|
||||
|
||||
|
||||
|
||||
#include <libintl.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <System.h>
|
||||
#include <Desktop.h>
|
||||
#include "common.h"
|
||||
#include "tab.h"
|
||||
#include "terminal.h"
|
||||
#include "window.h"
|
||||
#include "widget.h"
|
||||
#include "../config.h"
|
||||
#define _(string) gettext(string)
|
||||
#define N_(string) (string)
|
||||
|
||||
/* constants */
|
||||
#ifndef PROGNAME_TERMINAL
|
||||
# define PROGNAME_TERMINAL "terminal"
|
||||
#endif
|
||||
|
||||
|
||||
/* TerminalWidget */
|
||||
/* private */
|
||||
/* types */
|
||||
struct _TerminalWidget
|
||||
{
|
||||
Terminal * terminal;
|
||||
|
||||
TerminalTab ** tabs;
|
||||
size_t tabs_cnt;
|
||||
|
||||
/* widgets */
|
||||
GtkWidget * widget;
|
||||
#ifndef EMBEDDED
|
||||
GtkWidget * menubar;
|
||||
#endif
|
||||
GtkWidget * about;
|
||||
GtkToolItem * fullscreen;
|
||||
GtkWidget * notebook;
|
||||
};
|
||||
|
||||
|
||||
/* prototypes */
|
||||
static void _terminalwidget_tab_close(TerminalWidget * widget, unsigned int i);
|
||||
|
||||
/* callbacks */
|
||||
static void _terminalwidget_on_close(gpointer data);
|
||||
static void _terminalwidget_on_copy(gpointer data);
|
||||
static void _terminalwidget_on_fullscreen(gpointer data);
|
||||
static void _terminalwidget_on_new_tab(gpointer data);
|
||||
static void _terminalwidget_on_new_window(gpointer data);
|
||||
static void _terminalwidget_on_paste(gpointer data);
|
||||
|
||||
#ifndef EMBEDDED
|
||||
static void _terminalwidget_on_file_close(gpointer data);
|
||||
static void _terminalwidget_on_file_close_all(gpointer data);
|
||||
static void _terminalwidget_on_file_new_tab(gpointer data);
|
||||
static void _terminalwidget_on_file_new_window(gpointer data);
|
||||
static void _terminalwidget_on_edit_copy(gpointer data);
|
||||
static void _terminalwidget_on_edit_paste(gpointer data);
|
||||
static void _terminalwidget_on_view_fullscreen(gpointer data);
|
||||
static void _terminalwidget_on_help_about(gpointer data);
|
||||
static void _terminalwidget_on_help_contents(gpointer data);
|
||||
#endif
|
||||
|
||||
|
||||
/* constants */
|
||||
static char const * _authors[] =
|
||||
{
|
||||
"Pierre Pronchery <khorben@defora.org>",
|
||||
NULL
|
||||
};
|
||||
|
||||
#ifndef EMBEDDED
|
||||
/* menubar */
|
||||
static const DesktopMenu _terminalwidget_file_menu[] =
|
||||
{
|
||||
{ N_("New _tab"), G_CALLBACK(_terminalwidget_on_file_new_tab),
|
||||
"tab-new", GDK_CONTROL_MASK, GDK_KEY_T },
|
||||
{ N_("_New window"), G_CALLBACK(_terminalwidget_on_file_new_window),
|
||||
"window-new", GDK_CONTROL_MASK, GDK_KEY_N },
|
||||
{ "", NULL, NULL, 0, 0 },
|
||||
{ N_("_Close"), G_CALLBACK(_terminalwidget_on_file_close),
|
||||
GTK_STOCK_CLOSE, GDK_CONTROL_MASK, GDK_KEY_W },
|
||||
{ N_("Close all tabs"), G_CALLBACK(_terminalwidget_on_file_close_all),
|
||||
NULL, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_KEY_W },
|
||||
{ NULL, NULL, NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static const DesktopMenu _terminalwidget_edit_menu[] =
|
||||
{
|
||||
{ N_("_Copy"), G_CALLBACK(_terminalwidget_on_edit_copy),
|
||||
GTK_STOCK_COPY, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_KEY_C },
|
||||
{ N_("_Paste"), G_CALLBACK(_terminalwidget_on_edit_paste),
|
||||
GTK_STOCK_PASTE, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_KEY_V },
|
||||
{ NULL, NULL, NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static const DesktopMenu _terminalwidget_view_menu[] =
|
||||
{
|
||||
{ N_("_Fullscreen"), G_CALLBACK(_terminalwidget_on_view_fullscreen),
|
||||
# if GTK_CHECK_VERSION(2, 8, 0)
|
||||
GTK_STOCK_FULLSCREEN,
|
||||
# else
|
||||
NULL,
|
||||
# endif
|
||||
0, GDK_KEY_F11 },
|
||||
{ NULL, NULL, NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static const DesktopMenu _terminalwidget_help_menu[] =
|
||||
{
|
||||
{ N_("_Contents"), G_CALLBACK(_terminalwidget_on_help_contents),
|
||||
"help-contents", 0, GDK_KEY_F1 },
|
||||
#if GTK_CHECK_VERSION(2, 6, 0)
|
||||
{ N_("_About"), G_CALLBACK(_terminalwidget_on_help_about),
|
||||
GTK_STOCK_ABOUT, 0, 0 },
|
||||
#else
|
||||
{ N_("_About"), G_CALLBACK(_terminalwidget_on_help_about), NULL, 0, 0 },
|
||||
#endif
|
||||
{ NULL, NULL, NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static const DesktopMenubar _terminalwidget_menubar[] =
|
||||
{
|
||||
{ N_("_File"), _terminalwidget_file_menu },
|
||||
{ N_("_Edit"), _terminalwidget_edit_menu },
|
||||
{ N_("_View"), _terminalwidget_view_menu },
|
||||
{ N_("_Help"), _terminalwidget_help_menu },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
#endif
|
||||
|
||||
static DesktopToolbar _terminalwidget_toolbar[] =
|
||||
{
|
||||
{ N_("New tab"), G_CALLBACK(_terminalwidget_on_new_tab), "tab-new", 0,
|
||||
0, NULL },
|
||||
{ N_("New window"), G_CALLBACK(_terminalwidget_on_new_window),
|
||||
"window-new", 0, 0, NULL },
|
||||
{ "", NULL, NULL, 0, 0, NULL },
|
||||
{ N_("Copy"), G_CALLBACK(_terminalwidget_on_copy), GTK_STOCK_COPY, 0,
|
||||
0, NULL },
|
||||
{ N_("Paste"), G_CALLBACK(_terminalwidget_on_paste), GTK_STOCK_PASTE, 0,
|
||||
0, NULL },
|
||||
{ "", NULL, NULL, 0, 0, NULL },
|
||||
{ NULL, NULL, NULL, 0, 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
/* public */
|
||||
/* functions */
|
||||
/* terminalwidget_new */
|
||||
TerminalWidget * terminalwidget_new(Terminal * terminal, GtkWidget * window)
|
||||
{
|
||||
TerminalWidget * widget;
|
||||
GtkAccelGroup * group;
|
||||
GtkWidget * vbox;
|
||||
GtkWidget * toolbar;
|
||||
GtkToolItem * toolitem;
|
||||
|
||||
if((widget = object_new(sizeof(*widget))) == NULL)
|
||||
return NULL;
|
||||
widget->terminal = terminal;
|
||||
widget->tabs = NULL;
|
||||
widget->tabs_cnt = 0;
|
||||
group = gtk_accel_group_new();
|
||||
widget->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
vbox = widget->widget;
|
||||
#ifndef EMBEDDED
|
||||
/* menubar */
|
||||
widget->menubar = desktop_menubar_create(_terminalwidget_menubar,
|
||||
widget, group);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), widget->menubar, FALSE, TRUE, 0);
|
||||
#endif
|
||||
widget->about = NULL;
|
||||
/* toolbar */
|
||||
toolbar = desktop_toolbar_create(_terminalwidget_toolbar, widget, group);
|
||||
#if GTK_CHECK_VERSION(2, 8, 0)
|
||||
toolitem = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_FULLSCREEN);
|
||||
#else
|
||||
toolitem = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_ZOOM_FIT);
|
||||
#endif
|
||||
widget->fullscreen = toolitem;
|
||||
g_signal_connect_swapped(G_OBJECT(toolitem), "toggled", G_CALLBACK(
|
||||
_terminalwidget_on_fullscreen), widget);
|
||||
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, TRUE, 0);
|
||||
gtk_window_add_accel_group(GTK_WINDOW(window), group);
|
||||
g_object_unref(group);
|
||||
/* view */
|
||||
widget->notebook = gtk_notebook_new();
|
||||
gtk_notebook_set_scrollable(GTK_NOTEBOOK(widget->notebook), TRUE);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), widget->notebook, TRUE, TRUE, 0);
|
||||
gtk_widget_show_all(vbox);
|
||||
return widget;
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_delete */
|
||||
void terminalwidget_delete(TerminalWidget * widget)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < widget->tabs_cnt; i++)
|
||||
terminaltab_delete(widget->tabs[i]);
|
||||
/* FIXME also take care of the sub-processes */
|
||||
free(widget->tabs);
|
||||
object_delete(widget);
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
/* terminalwidget_get_fullscreen */
|
||||
gboolean terminalwidget_get_fullscreen(TerminalWidget * widget)
|
||||
{
|
||||
TerminalWindow * window;
|
||||
|
||||
window = terminal_get_window(widget->terminal);
|
||||
return terminalwindow_get_fullscreen(window);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_get_widget */
|
||||
GtkWidget * terminalwidget_get_widget(TerminalWidget * widget)
|
||||
{
|
||||
return widget->widget;
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_set_fullscreen */
|
||||
void terminalwidget_set_fullscreen(TerminalWidget * widget,
|
||||
gboolean fullscreen)
|
||||
{
|
||||
TerminalWindow * window;
|
||||
|
||||
#ifndef EMBEDDED
|
||||
if(fullscreen)
|
||||
gtk_widget_hide(widget->menubar);
|
||||
else
|
||||
gtk_widget_show(widget->menubar);
|
||||
#endif
|
||||
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(
|
||||
widget->fullscreen), fullscreen);
|
||||
window = terminal_get_window(widget->terminal);
|
||||
terminalwindow_set_fullscreen(window, fullscreen);
|
||||
}
|
||||
|
||||
|
||||
/* useful */
|
||||
/* interface */
|
||||
/* terminalwidget_show_about */
|
||||
static gboolean _show_about_on_closex(gpointer data);
|
||||
|
||||
void terminalwidget_show_about(TerminalWidget * widget, gboolean show)
|
||||
{
|
||||
TerminalWindow * twindow;
|
||||
GtkWidget * window;
|
||||
|
||||
if(widget->about == NULL)
|
||||
{
|
||||
twindow = terminal_get_window(widget->terminal);
|
||||
window = terminalwindow_get_window(twindow);
|
||||
widget->about = desktop_about_dialog_new();
|
||||
gtk_window_set_modal(GTK_WINDOW(widget->about), TRUE);
|
||||
gtk_window_set_transient_for(GTK_WINDOW(widget->about),
|
||||
GTK_WINDOW(window));
|
||||
desktop_about_dialog_set_authors(widget->about, _authors);
|
||||
desktop_about_dialog_set_comments(widget->about,
|
||||
_("Terminal for the DeforaOS desktop"));
|
||||
desktop_about_dialog_set_copyright(widget->about, _copyright);
|
||||
desktop_about_dialog_set_license(widget->about, _license);
|
||||
desktop_about_dialog_set_logo_icon_name(widget->about,
|
||||
"terminal");
|
||||
desktop_about_dialog_set_program_name(widget->about, PACKAGE);
|
||||
desktop_about_dialog_set_version(widget->about, VERSION);
|
||||
desktop_about_dialog_set_website(widget->about,
|
||||
"https://www.defora.org/");
|
||||
g_signal_connect_swapped(widget->about, "delete-event",
|
||||
G_CALLBACK(_show_about_on_closex), widget);
|
||||
}
|
||||
if(show)
|
||||
gtk_widget_show(widget->about);
|
||||
else
|
||||
gtk_widget_hide(widget->about);
|
||||
}
|
||||
|
||||
static gboolean _show_about_on_closex(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
|
||||
gtk_widget_hide(widget->about);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_show_preferences */
|
||||
void terminalwidget_show_preferences(TerminalWidget * terminal, gboolean show)
|
||||
{
|
||||
/* FIXME implement */
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_tab_close */
|
||||
void terminalwidget_tab_close(TerminalWidget * widget, TerminalTab * tab)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < widget->tabs_cnt; i++)
|
||||
if(widget->tabs[i] == tab)
|
||||
{
|
||||
_terminalwidget_tab_close(widget, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_tab_close_all */
|
||||
static gboolean _tab_close_all_confirm(TerminalWidget * widget);
|
||||
|
||||
void terminalwidget_tab_close_all(TerminalWidget * widget)
|
||||
{
|
||||
if(widget->tabs_cnt > 1 && _tab_close_all_confirm(widget) != TRUE)
|
||||
return;
|
||||
while(widget->tabs_cnt > 0)
|
||||
_terminalwidget_tab_close(widget, widget->tabs_cnt - 1);
|
||||
}
|
||||
|
||||
static gboolean _tab_close_all_confirm(TerminalWidget * widget)
|
||||
{
|
||||
TerminalWindow * twindow;
|
||||
GtkWidget * window;
|
||||
GtkWidget * dialog;
|
||||
gboolean res;
|
||||
|
||||
twindow = terminal_get_window(widget->terminal);
|
||||
window = terminalwindow_get_window(twindow);
|
||||
dialog = gtk_message_dialog_new(GTK_WINDOW(window),
|
||||
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
|
||||
#if GTK_CHECK_VERSION(2, 6, 0)
|
||||
"%s", _("Question"));
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
||||
#endif
|
||||
"%s", _("There are multiple tabs opened.\n"
|
||||
"Do you really want to close every tab"
|
||||
" opened in this window?"));
|
||||
gtk_dialog_add_buttons(GTK_DIALOG(dialog),
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
|
||||
gtk_window_set_title(GTK_WINDOW(dialog), _("Question"));
|
||||
res = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
return (res == GTK_RESPONSE_CLOSE) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_tab_open */
|
||||
TerminalTab * terminalwidget_tab_open(TerminalWidget * widget)
|
||||
{
|
||||
TerminalTab ** p;
|
||||
TerminalTab * tab;
|
||||
GtkWidget * label;
|
||||
GtkWidget * child;
|
||||
|
||||
if((p = realloc(widget->tabs, sizeof(*p) * (widget->tabs_cnt + 1)))
|
||||
== NULL)
|
||||
return NULL;
|
||||
widget->tabs = p;
|
||||
if((tab = terminaltab_new(widget->terminal)) == NULL)
|
||||
return NULL;
|
||||
widget->tabs[widget->tabs_cnt++] = tab;
|
||||
label = terminaltab_get_label(tab);
|
||||
child = terminaltab_get_widget(tab);
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(widget->notebook), child, label);
|
||||
#if GTK_CHECK_VERSION(2, 10, 0)
|
||||
gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(widget->notebook), child,
|
||||
TRUE);
|
||||
#endif
|
||||
return tab;
|
||||
}
|
||||
|
||||
|
||||
/* private */
|
||||
/* terminalwidget_tab_close */
|
||||
static void _terminalwidget_tab_close(TerminalWidget * widget, unsigned int i)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(%u)\n", __func__, i);
|
||||
#endif
|
||||
if(i >= widget->tabs_cnt)
|
||||
return;
|
||||
terminaltab_delete(widget->tabs[i]);
|
||||
gtk_notebook_remove_page(GTK_NOTEBOOK(widget->notebook), i);
|
||||
memmove(&widget->tabs[i], &widget->tabs[i + 1],
|
||||
(widget->tabs_cnt - (i + 1)) * sizeof(*widget->tabs));
|
||||
if(--widget->tabs_cnt == 0)
|
||||
/* XXX there might be multiple windows opened */
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
|
||||
/* callbacks */
|
||||
/* terminalwidget_on_close */
|
||||
static void _terminalwidget_on_close(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
int i;
|
||||
|
||||
i = gtk_notebook_get_current_page(GTK_NOTEBOOK(widget->notebook));
|
||||
if(i < 0)
|
||||
return;
|
||||
_terminalwidget_tab_close(widget, i);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_copy */
|
||||
static void _terminalwidget_on_copy(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
int i;
|
||||
|
||||
i = gtk_notebook_get_current_page(GTK_NOTEBOOK(widget->notebook));
|
||||
if(i < 0)
|
||||
return;
|
||||
terminaltab_clipboard_copy(widget->tabs[i]);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_fullscreen */
|
||||
static void _terminalwidget_on_fullscreen(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
TerminalWindow * window;
|
||||
|
||||
window = terminal_get_window(widget->terminal);
|
||||
terminalwindow_set_fullscreen(window,
|
||||
terminalwindow_get_fullscreen(window) ? FALSE : TRUE);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_new_tab */
|
||||
static void _terminalwidget_on_new_tab(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
|
||||
terminalwidget_tab_open(widget);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_new_window */
|
||||
static void _terminalwidget_on_new_window(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
|
||||
/* XXX may fail */
|
||||
terminal_window_open(widget->terminal);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_paste */
|
||||
static void _terminalwidget_on_paste(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
int i;
|
||||
|
||||
i = gtk_notebook_get_current_page(GTK_NOTEBOOK(widget->notebook));
|
||||
if(i < 0)
|
||||
return;
|
||||
terminaltab_clipboard_paste(widget->tabs[i]);
|
||||
}
|
||||
|
||||
|
||||
#ifndef EMBEDDED
|
||||
/* terminalwidget_on_edit_copy */
|
||||
static void _terminalwidget_on_edit_copy(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
|
||||
_terminalwidget_on_copy(widget);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_edit_paste */
|
||||
static void _terminalwidget_on_edit_paste(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
|
||||
_terminalwidget_on_paste(widget);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_file_close */
|
||||
static void _terminalwidget_on_file_close(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
|
||||
_terminalwidget_on_close(widget);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_file_close_all */
|
||||
static void _terminalwidget_on_file_close_all(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
|
||||
terminalwidget_tab_close_all(widget);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_file_new_tab */
|
||||
static void _terminalwidget_on_file_new_tab(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
|
||||
terminalwidget_tab_open(widget);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_file_new_window */
|
||||
static void _terminalwidget_on_file_new_window(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
|
||||
terminal_window_open(widget->terminal);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_help_about */
|
||||
static void _terminalwidget_on_help_about(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
|
||||
terminalwidget_show_about(widget, TRUE);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_help_contents */
|
||||
static void _terminalwidget_on_help_contents(gpointer data)
|
||||
{
|
||||
(void) data;
|
||||
|
||||
desktop_help_contents(PACKAGE, PROGNAME_TERMINAL);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwidget_on_view_fullscreen */
|
||||
static void _terminalwidget_on_view_fullscreen(gpointer data)
|
||||
{
|
||||
TerminalWidget * widget = data;
|
||||
|
||||
_terminalwidget_on_fullscreen(widget);
|
||||
}
|
||||
#endif
|
59
src/widget.h
Normal file
59
src/widget.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Desktop Terminal */
|
||||
/* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
|
||||
|
||||
#ifndef TERMINAL_WIDGET_H
|
||||
# define TERMINAL_WIDGET_H
|
||||
|
||||
# include "common.h"
|
||||
|
||||
|
||||
/* TerminalWidget */
|
||||
/* public */
|
||||
/* functions */
|
||||
TerminalWidget * terminalwidget_new(Terminal * terminal, GtkWidget * window);
|
||||
void terminalwidget_delete(TerminalWidget * widget);
|
||||
|
||||
|
||||
/* accessors */
|
||||
gboolean terminalwidget_get_fullscreen(TerminalWidget * widget);
|
||||
void terminalwidget_set_fullscreen(TerminalWidget * widget,
|
||||
gboolean fullscreen);
|
||||
|
||||
GtkWidget * terminalwidget_get_widget(TerminalWidget * widget);
|
||||
|
||||
|
||||
/* useful */
|
||||
/* interface */
|
||||
void terminalwidget_show_about(TerminalWidget * widget, gboolean show);
|
||||
void terminalwidget_show_preferences(TerminalWidget * widget, gboolean show);
|
||||
|
||||
void terminalwidget_tab_close(TerminalWidget * widget, TerminalTab * tab);
|
||||
void terminalwidget_tab_close_all(TerminalWidget * widget);
|
||||
TerminalTab * terminalwidget_tab_open(TerminalWidget * widget);
|
||||
|
||||
#endif /* !TERMINAL_WIDGET_H */
|
159
src/window.c
Normal file
159
src/window.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Desktop Terminal */
|
||||
/* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
|
||||
|
||||
#include <libintl.h>
|
||||
#include <System.h>
|
||||
#include "widget.h"
|
||||
#include "window.h"
|
||||
#define _(string) gettext(string)
|
||||
|
||||
|
||||
/* TerminalWindow */
|
||||
/* private */
|
||||
/* types */
|
||||
struct _TerminalWindow
|
||||
{
|
||||
Terminal * terminal;
|
||||
TerminalWidget * widget;
|
||||
gboolean fullscreen;
|
||||
|
||||
/* widgets */
|
||||
GtkWidget * window;
|
||||
};
|
||||
|
||||
|
||||
/* prototypes */
|
||||
/* callbacks */
|
||||
static gboolean _terminalwindow_on_closex(gpointer data);
|
||||
|
||||
|
||||
/* public */
|
||||
/* functions */
|
||||
/* terminalwindow_new */
|
||||
TerminalWindow * terminalwindow_new(Terminal * terminal)
|
||||
{
|
||||
TerminalWindow * window;
|
||||
GtkWidget * widget;
|
||||
|
||||
if((window = object_new(sizeof(*window))) == NULL)
|
||||
return NULL;
|
||||
window->terminal = terminal;
|
||||
window->fullscreen = FALSE;
|
||||
window->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
if((window->widget = terminalwidget_new(terminal, window->window))
|
||||
== NULL)
|
||||
{
|
||||
terminalwindow_delete(window);
|
||||
return NULL;
|
||||
}
|
||||
/* XXX really default to 80x24 (or a terminal size) */
|
||||
gtk_window_set_default_size(GTK_WINDOW(window->window), 600, 400);
|
||||
#if GTK_CHECK_VERSION(2, 6, 0)
|
||||
gtk_window_set_icon_name(GTK_WINDOW(window->window), "terminal");
|
||||
#endif
|
||||
gtk_window_set_title(GTK_WINDOW(window->window), _("Terminal"));
|
||||
g_signal_connect_swapped(window->window, "delete-event", G_CALLBACK(
|
||||
_terminalwindow_on_closex), window);
|
||||
widget = terminalwidget_get_widget(window->widget);
|
||||
gtk_container_add(GTK_CONTAINER(window->window), widget);
|
||||
gtk_widget_show(window->window);
|
||||
return window;
|
||||
}
|
||||
|
||||
|
||||
/* terminalwindow_delete */
|
||||
void terminalwindow_delete(TerminalWindow * window)
|
||||
{
|
||||
if(window->widget != NULL)
|
||||
terminalwidget_delete(window->widget);
|
||||
gtk_widget_destroy(window->window);
|
||||
object_delete(window);
|
||||
}
|
||||
|
||||
|
||||
/* accessors */
|
||||
/* terminalwindow_get_fullscreen */
|
||||
gboolean terminalwindow_get_fullscreen(TerminalWindow * window)
|
||||
{
|
||||
return window->fullscreen;
|
||||
}
|
||||
|
||||
|
||||
/* terminalwindow_get_widget */
|
||||
TerminalWidget * terminalwindow_get_widget(TerminalWindow * window)
|
||||
{
|
||||
return window->widget;
|
||||
}
|
||||
|
||||
|
||||
/* terminalwindow_get_widget */
|
||||
GtkWidget * terminalwindow_get_window(TerminalWindow * window)
|
||||
{
|
||||
return window->window;
|
||||
}
|
||||
|
||||
|
||||
/* terminalwindow_set_fullscreen */
|
||||
void terminalwindow_set_fullscreen(TerminalWindow * window, gboolean fullscreen)
|
||||
{
|
||||
if(fullscreen == window->fullscreen)
|
||||
return;
|
||||
window->fullscreen = fullscreen;
|
||||
terminalwidget_set_fullscreen(window->widget, fullscreen);
|
||||
if(fullscreen)
|
||||
gtk_window_fullscreen(GTK_WINDOW(window->window));
|
||||
else
|
||||
gtk_window_unfullscreen(GTK_WINDOW(window->window));
|
||||
}
|
||||
|
||||
|
||||
/* useful */
|
||||
/* terminalwindow_show_about */
|
||||
void terminalwindow_show_about(TerminalWindow * terminal, gboolean show)
|
||||
{
|
||||
terminalwidget_show_about(terminal->widget, show);
|
||||
}
|
||||
|
||||
|
||||
/* terminalwindow_show_preferences */
|
||||
void terminalwindow_show_preferences(TerminalWindow * terminal, gboolean show)
|
||||
{
|
||||
terminalwidget_show_preferences(terminal->widget, show);
|
||||
}
|
||||
|
||||
|
||||
/* private */
|
||||
/* callbacks */
|
||||
/* terminalwindow_on_closex */
|
||||
static gboolean _terminalwindow_on_closex(gpointer data)
|
||||
{
|
||||
TerminalWindow * window = data;
|
||||
|
||||
terminalwidget_tab_close_all(window->widget);
|
||||
return TRUE;
|
||||
}
|
55
src/window.h
Normal file
55
src/window.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2018 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS Desktop Terminal */
|
||||
/* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
|
||||
|
||||
#ifndef TERMINAL_WINDOW_H
|
||||
# define TERMINAL_WINDOW_H
|
||||
|
||||
# include "common.h"
|
||||
|
||||
|
||||
/* TerminalWindow */
|
||||
/* public */
|
||||
/* functions */
|
||||
TerminalWindow * terminalwindow_new(Terminal * terminal);
|
||||
void terminalwindow_delete(TerminalWindow * window);
|
||||
|
||||
|
||||
/* accessors */
|
||||
gboolean terminalwindow_get_fullscreen(TerminalWindow * window);
|
||||
void terminalwindow_set_fullscreen(TerminalWindow * window,
|
||||
gboolean fullscreen);
|
||||
|
||||
TerminalWidget * terminalwindow_get_widget(TerminalWindow * window);
|
||||
GtkWidget * terminalwindow_get_window(TerminalWindow * window);
|
||||
|
||||
/* useful */
|
||||
/* interface */
|
||||
void terminalwindow_show_about(TerminalWindow * terminal, gboolean show);
|
||||
void terminalwindow_show_preferences(TerminalWindow * terminal, gboolean show);
|
||||
|
||||
#endif /* !TERMINAL_WINDOW_H */
|
Loading…
Reference in New Issue
Block a user