From 20d518389a6d2e2cac761d62890c8321397d292a Mon Sep 17 00:00:00 2001
From: Marty Jack <martyj@linux.local>
Date: Mon, 29 Mar 2010 16:50:48 -0400
Subject: [PATCH 09/60] Major rework
- -e and --command now consume arguments to the end of the line (--command= is unchanged)
- Preference dialog now GtkBuilder based, must have external XML file to operate successfully
- 2973537 Failure to either connect or bind to the communication socket now handled gracefully; the LXTerminal will run standalone
- Terminal failed to resize when font changed from larger to smaller
- Failed to honor --working-directory with --command
- Configuration now applies immediately
- User preference for cursor shape
- User preference for audible bell
- 2977944 User preference for allow bold
- 2842542 User preference for hide Close button
- 2842542 Middle click on tab closes it; consistent with other applications such as Firefox
- 2845142 User can edit tab labels
---
AUTHORS | 1 +
configure.ac | 2 +-
data/Makefile.am | 15 +
data/lxterminal-preferences.glade | 512 ++++++++++
data/lxterminal.conf.in | 1 +
man/lxterminal.xml | 30 +-
src/Makefile.am | 7 +-
src/lxterminal.c | 2017 ++++++++++++++++++++-----------------
src/lxterminal.h | 111 ++-
src/preferences.c | 526 ++++------
src/preferences.h | 78 +-
src/setting.c | 208 ++--
src/setting.h | 58 +-
src/tab.c | 112 +--
src/tab.h | 29 +-
src/unixsocket.c | 361 ++++---
src/unixsocket.h | 22 +-
17 files changed, 2361 insertions(+), 1729 deletions(-)
create mode 100644 data/lxterminal-preferences.glade
diff --git a/AUTHORS b/AUTHORS
index 975d44a..e976153 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -4,6 +4,7 @@ Alessandro Pellizzari <alex_shu@users.sourceforge.net>
Micahel <metsger@users.sourceforge.net>
Yotam Medini <yotam.medini@gmail.com>
Liu Yubao <yubao.liu@gmail.com>
+Marty Jack <martyj19@comcast.net>
Icon:
Taken from "nuoveXT 2" icon theme created by Alexandre Moore (saki)
diff --git a/configure.ac b/configure.ac
index d3942c2..120deea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -21,7 +21,7 @@ AC_ARG_ENABLE(man,
)
# Checks for libraries.
PKG_CHECK_MODULES(glib, [glib-2.0 >= 2.6.0])
-PKG_CHECK_MODULES(gtk, [gtk+-2.0 >= 2.6.0])
+PKG_CHECK_MODULES(gtk, [gtk+-2.0 >= 2.12.0])
PKG_CHECK_MODULES(vte, [vte >= 0.17.1])
CFLAGS="$CFLAGS $glib_CFLAGS $gtk_CFLAGS $vte_CFLAGS"
LIBS="$LIBS $glib_LIBS $gtk_LIBS $vte_LIBS"
diff --git a/data/Makefile.am b/data/Makefile.am
index a0eacd4..046918a 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1,6 +1,20 @@
default_config_DATA = lxterminal.conf
default_configdir = $(datadir)/lxterminal
+uidir=$(datadir)/lxterminal
+ui_in_files= \
+ lxterminal-preferences.glade
+
+ui_DATA = $(ui_in_files:.glade=.ui)
+
+# Generate GtkBuilder UI files from Glade files
+%.ui: %.glade
+ cp $< $@
+ $(top_builddir)/src/xml-purge $@
+
+CLEANFILES = \
+ $(ui_DATA)
+
lxterminal.desktop_in_files = lxterminal.desktop.in
lxterminal.desktop.in_DATA = $(lxterminal.desktop_in_files:.desktop.in=.desktop)
@INTLTOOL_DESKTOP_RULE@
@@ -13,4 +27,5 @@ EXTRA_DIST = \
lxterminal.conf.in \
$(lxterminal_images_DATA) \
$(lxterminal.desktop.in_DATA) \
+ $(ui_DATA) \
$(default_config_DATA)
diff --git a/data/lxterminal-preferences.glade b/data/lxterminal-preferences.glade
new file mode 100644
index 0000000..6b9ebaf
--- /dev/null
+++ b/data/lxterminal-preferences.glade
@@ -0,0 +1,512 @@
+<?xml version="1.0"?>
+<interface>
+ <!-- interface-requires gtk+ 2.12 -->
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkListStore" id="liststore1">
+ <columns>
+ <!-- column-name gchararray1 -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Top</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Bottom</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Left</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Right</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkDialog" id="lxterminal_preferences">
+ <property name="border_width">5</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkNotebook" id="notebook1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">8</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">5</property>
+ <property name="row_spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Terminal font</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFontButton" id="terminal_font">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Background</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="background_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_alpha">True</property>
+ <property name="color">#000000000000</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="foreground_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="color">#000000000000</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Foreground</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Allow bold font</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="allow_bold">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Cursor blink</property>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="cursor_blink">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Cursor style</property>
+ </object>
+ <packing>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="cursor_style_block">
+ <property name="label" translatable="yes">Block</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="cursor_style_underline">
+ <property name="label" translatable="yes">Underline</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">cursor_style_block</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label17">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Audible bell</property>
+ </object>
+ <packing>
+ <property name="top_attach">7</property>
+ <property name="bottom_attach">8</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="audible_bell">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">7</property>
+ <property name="bottom_attach">8</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Style</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table2">
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">5</property>
+ <property name="row_spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Tab panel position</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Scrollback lines</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Hide scroll bar</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Hide menu bar</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="hide_menu_bar">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="tab_position">
+ <property name="visible">True</property>
+ <property name="model">liststore1</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options">GTK_SHRINK</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="scrollback_lines">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="adjustment">scrollback_lines_adjustment</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="hide_scroll_bar">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Hide Close buttons</property>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="hide_close_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Display</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table3">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">5</property>
+ <property name="row_spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="label14">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Select-by-word characters</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Disable menu shortcut key (F10 by default)</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="disable_f10">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="select_by_word">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Advanced</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="Cancel_button">
+ <property name="label" translatable="yes">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="OK_button">
+ <property name="label" translatable="yes">gtk-ok</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">Cancel_button</action-widget>
+ <action-widget response="-5">OK_button</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkAdjustment" id="scrollback_lines_adjustment">
+ <property name="value">1000</property>
+ <property name="upper">100000</property>
+ <property name="step_increment">10</property>
+ <property name="page_increment">10</property>
+ </object>
+</interface>
diff --git a/data/lxterminal.conf.in b/data/lxterminal.conf.in
index 74ec5cb..2621a08 100644
--- a/data/lxterminal.conf.in
+++ b/data/lxterminal.conf.in
@@ -1,3 +1,4 @@
[general]
fontname=Monospace 10
selchars=-A-Za-z0-9,./?%&#:_
+scrollback=1000
diff --git a/man/lxterminal.xml b/man/lxterminal.xml
index c2124eb..e0977cf 100644
--- a/man/lxterminal.xml
+++ b/man/lxterminal.xml
@@ -29,8 +29,7 @@
<para><command>lxterminal</command> is a program that provides a terminal
emulator
- for the desktop, usually for LXDE. It is a lightweight GTK+ 2.x based desktop
- panel.
+ for the desktop, usually for LXDE.
</para>
</refsect1>
@@ -44,19 +43,11 @@
<variablelist> <varlistentry> <term> <option>-e <replaceable>STRING</replaceable></option>
<option>--command=<replaceable>STRING</replaceable></option>
+ <option>--command <replaceable>STRING</replaceable></option>
+
</term>
- <listitem> <para>Execute the argument to this option inside the terminal.</para>
- </listitem>
- </varlistentry>
- <varlistentry> <term> <option>-t <replaceable>STRING</replaceable></option>
- <option>--title=<replaceable>STRING</replaceable></option>
- </term>
- <listitem> <para>Set the terminal's title.</para>
- </listitem>
- </varlistentry>
- <varlistentry> <term> <option>--working-directory=<replaceable>DIRECTORY</replaceable></option>
- </term>
- <listitem> <para>Set the terminal's working directory.</para>
+ <listitem> <para>This option specifies the program (and its command line arguments) to be run in the terminal.
+Except in the <option>--command=</option> form, this must be the last option on the command line.</para>
</listitem>
</varlistentry>
<varlistentry> <term> <option>--geometry=<replaceable>CHARACTERS</replaceable>x<replaceable>LINES</replaceable></option>
@@ -70,6 +61,17 @@
<listitem> <para>Executes login shell.</para>
</listitem>
</varlistentry>
+ <varlistentry> <term> <option>-t <replaceable>STRING</replaceable></option>
+ <option>--title=<replaceable>STRING</replaceable></option>
+ </term>
+ <listitem> <para>Set the terminal's title.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry> <term> <option>--working-directory=<replaceable>DIRECTORY</replaceable></option>
+ </term>
+ <listitem> <para>Set the terminal's working directory.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/src/Makefile.am b/src/Makefile.am
index ca2b3db..af9efd4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,8 +15,6 @@ lxterminal_SOURCES = \
unixsocket.c \
setting.h \
setting.c \
- tab.h \
- tab.c \
lxterminal.h \
lxterminal.c \
preferences.h \
@@ -25,3 +23,8 @@ lxterminal_SOURCES = \
lxterminal_LDADD = \
$(PACKAGE_LIBS) \
$(INTLLIBS)
+
+noinst_PROGRAMS=xml-purge
+xml_purge_SOURCES=xml-purge.c
+xml_purge_CFLAGS=@CFLAGS@
+xml_purge_LDADD=@LIBS@
diff --git a/src/lxterminal.c b/src/lxterminal.c
index 37e0253..60712bb 100644
--- a/src/lxterminal.c
+++ b/src/lxterminal.c
@@ -1,5 +1,6 @@
-/*
+/**
* Copyright 2008 Fred Chien <cfsghost@gmail.com>
+ * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
*
* 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
@@ -18,7 +19,7 @@
*/
#ifdef HAVE_CONFIG_H
- #include <config.h>
+#include <config.h>
#endif
#include <X11/Xutil.h>
@@ -29,14 +30,14 @@
#include <vte/vte.h>
#include <langinfo.h>
#include <locale.h>
+#include <sys/stat.h>
#include "lxterminal.h"
#include "setting.h"
-#include "tab.h"
#include "preferences.h"
#include "unixsocket.h"
-/* Linux color for palette */
+/* Linux color for palette. */
static const GdkColor linux_color[16] =
{
{ 0, 0x0000, 0x0000, 0x0000 },
@@ -57,1100 +58,1272 @@ static const GdkColor linux_color[16] =
{ 0, 0xffff, 0xffff, 0xffff }
};
-static void terminal_childexit(VteTerminal *vte, Term *term);
-
-static Term *terminal_new(LXTerminal *terminal, const gchar *label, const gchar *pwd, gchar **env, const gchar *exec);
-static void terminal_free(Term* term);
-
-/* menu accel saved when the user disables it */
-static char *saved_menu_accel = NULL;
-
-static gchar helpmsg[] = {
+/* X accessor. */
+static void gdk_window_get_geometry_hints(GdkWindow * window, GdkGeometry * geometry, GdkWindowHints * geometry_mask);
+
+/* Utilities. */
+static void terminal_get_padding(Term * term, GtkBorder * border);
+static void terminal_geometry_restore(Term * term);
+static void terminal_tab_set_position(GtkWidget * notebook, gint tab_position);
+
+/* Menu and accelerator event handlers. */
+static void terminal_initialize_switch_tab_accelerator(Term * term);
+static void terminal_switch_tab_accelerator(Term * term);
+static void terminal_new_window_activate_event(GtkAction * action, LXTerminal * terminal);
+static void terminal_new_window_accelerator(LXTerminal * terminal, guint action, GtkWidget * item);
+static void terminal_new_tab_activate_event(GtkAction * action, LXTerminal * terminal);
+static void terminal_new_tab_accelerator(LXTerminal * terminal, guint action, GtkWidget * item);
+static void terminal_close_tab_activate_event(GtkAction * action, LXTerminal * terminal);
+static void terminal_close_tab_accelerator(LXTerminal * terminal, guint action, GtkWidget * item);
+static void terminal_copy_activate_event(GtkAction * action, LXTerminal * terminal);
+static void terminal_copy_accelerator(LXTerminal * terminal, guint action, GtkWidget * item);
+static void terminal_paste_activate_event(GtkAction * action, LXTerminal * terminal);
+static void terminal_paste_accelerator(LXTerminal * terminal, guint action, GtkWidget * item);
+static void terminal_name_tab_response_event(GtkWidget * dialog, gint response, LXTerminal * terminal);
+static void terminal_name_tab_activate_event(GtkAction * action, LXTerminal * terminal);
+static void terminal_name_tab_accelerator(LXTerminal * terminal, guint action, GtkWidget * item);
+static void terminal_previous_tab_activate_event(GtkAction * action, LXTerminal * terminal);
+static void terminal_previous_tab_accelerator(LXTerminal * terminal, guint action, GtkWidget * item);
+static void terminal_next_tab_activate_event(GtkAction * action, LXTerminal * terminal);
+static void terminal_next_tab_accelerator(LXTerminal * terminal, guint action, GtkWidget * item);
+static void terminal_move_tab_execute(LXTerminal * terminal, gint direction);
+static void terminal_move_tab_left_activate_event(GtkAction * action, LXTerminal * terminal);
+static void terminal_move_tab_left_accelerator(LXTerminal * terminal, guint action, GtkWidget * item);
+static void terminal_move_tab_right_activate_event(GtkAction * action, LXTerminal * terminal);
+static void terminal_move_tab_right_accelerator(LXTerminal * terminal, guint action, GtkWidget * item);
+static void terminal_about_activate_event(GtkAction * action, LXTerminal * terminal);
+
+/* Window creation, destruction, and control. */
+static gboolean terminal_window_size_request_event(GtkWidget * widget, GtkRequisition * requisition, LXTerminal * terminal);
+static void terminal_window_set_fixed_size(LXTerminal * terminal);
+static void terminal_switch_page_event(GtkNotebook * notebook, GtkNotebookPage * page, guint num, LXTerminal * terminal);
+static void terminal_window_title_changed_event(GtkWidget * vte, Term * term);
+static void terminal_window_exit(LXTerminal * terminal, GObject * where_the_object_was);
+static void terminal_child_exited_event(VteTerminal * vte, Term * term);
+static gboolean terminal_tab_button_press_event(GtkWidget * widget, GdkEventButton * event, Term * term);
+static gboolean terminal_vte_button_press_event(VteTerminal * vte, GdkEventButton * event, Term * term);
+static void terminal_settings_apply_to_term(LXTerminal * terminal, Term * term);
+static Term * terminal_new(LXTerminal * terminal, const gchar * label, const gchar * pwd, gchar * * env, const gchar * exec);
+static void terminal_free(Term * term);
+static void terminal_menubar_initialize(LXTerminal * terminal);
+static void terminal_accelerator_initialize(LXTerminal * terminal);
+static void terminal_menu_accelerator_update(LXTerminal * terminal);
+static void terminal_settings_apply(LXTerminal * terminal);
+
+/* Menu accelerator saved when the user disables it. */
+static char * saved_menu_accelerator = NULL;
+
+/* Help when user enters an invalid command. */
+static gchar usage_display[] = {
"Usage:\n"
" lxterminal [Options...] - LXTerminal is a terminal emulator\n\n"
"Options:\n"
" -e, --command=STRING Execute the argument to this option inside the terminal\n"
- " -t, -T, --title=STRING Set the terminal's title\n"
+ " --geometry=COLUMNSxROWS Set the terminal's size\n"
+ " -l, --loginshell Execute login shell\n"
+ " -t, -T, --title=STRING Set the terminal's title\n"
" --working-directory=DIRECTORY Set the terminal's working directory\n"
- " --geometry=GEOMETRY X geometry specification (see \"X\" man page), can be specified once per window to be opened.\n"
- " -l, --loginshell Executes login shell.\n"
};
+/* Descriptors for menu top level. */
static GtkActionEntry menus[] =
{
{ "File", NULL, N_("_File") },
{ "Edit", NULL, N_("_Edit") },
-// { "View", NULL, N_("_View") },
{ "Tabs", NULL, N_("_Tabs") },
{ "Help", NULL, N_("_Help") }
};
#define MENUBAR_MENU_COUNT G_N_ELEMENTS(menus)
-static void
-gdk_window_get_geometry_hints(GdkWindow *window,
- GdkGeometry *geometry,
- GdkWindowHints *geom_mask)
+/* Descriptors for menu bar items. */
+static GtkActionEntry menu_items[] =
{
- XSizeHints size_hints;
- glong junk_size_mask = 0;
-
- g_return_if_fail (GDK_IS_WINDOW (window));
- g_return_if_fail (geometry != NULL);
- g_return_if_fail (geom_mask != NULL);
-
- *geom_mask = 0;
-
- if (GDK_WINDOW_DESTROYED (window))
- return;
-
- if (!XGetWMNormalHints (GDK_WINDOW_XDISPLAY (window),
- GDK_WINDOW_XID (window),
- &size_hints,
- &junk_size_mask))
- return;
-
- if (size_hints.flags & PMinSize) {
- *geom_mask |= GDK_HINT_MIN_SIZE;
- geometry->min_width = size_hints.min_width;
- geometry->min_height = size_hints.min_height;
- }
-
- if (size_hints.flags & PMaxSize) {
- *geom_mask |= GDK_HINT_MAX_SIZE;
- geometry->max_width = MAX (size_hints.max_width, 1);
- geometry->max_height = MAX (size_hints.max_height, 1);
- }
-
- if (size_hints.flags & PResizeInc) {
- *geom_mask |= GDK_HINT_RESIZE_INC;
- geometry->width_inc = size_hints.width_inc;
- geometry->height_inc = size_hints.height_inc;
- }
-
- if (size_hints.flags & PAspect) {
- *geom_mask |= GDK_HINT_ASPECT;
- geometry->min_aspect = (gdouble) size_hints.min_aspect.x / (gdouble) size_hints.min_aspect.y;
- geometry->max_aspect = (gdouble) size_hints.max_aspect.x / (gdouble) size_hints.max_aspect.y;
- }
-
- if (size_hints.flags & PWinGravity) {
- *geom_mask |= GDK_HINT_WIN_GRAVITY;
- geometry->win_gravity = size_hints.win_gravity;
- }
-}
+ { "File_NewWindow", GTK_STOCK_ADD, N_("New _Window"), NEW_WINDOW_ACCEL, "New Window", G_CALLBACK(terminal_new_window_activate_event) },
+ { "File_NewTab", GTK_STOCK_ADD, N_("New _Tab"), NEW_TAB_ACCEL, "New Tab", G_CALLBACK(terminal_new_tab_activate_event) },
+ { "File_Sep1", NULL, "Sep" },
+ { "File_CloseTab", GTK_STOCK_CLOSE, N_("_Close Tab"), CLOSE_TAB_ACCEL, "Close Tab", G_CALLBACK(terminal_close_tab_activate_event) },
+ { "File_Quit", GTK_STOCK_QUIT, N_("_Quit"), QUIT_ACCEL, "Quit", G_CALLBACK(gtk_main_quit) },
+ { "Edit_Copy", GTK_STOCK_COPY, N_("Cop_y"), COPY_ACCEL, "Copy", G_CALLBACK(terminal_copy_activate_event) },
+ { "Edit_Paste", GTK_STOCK_PASTE, N_("_Paste"), PASTE_ACCEL, "Paste", G_CALLBACK(terminal_paste_activate_event) },
+ { "Edit_Sep1", NULL, "Sep" },
+ { "Edit_Preferences", GTK_STOCK_EXECUTE, N_("Preference_s"), NULL, "Preferences", G_CALLBACK(terminal_preferences_dialog) },
+ { "Tabs_NameTab", GTK_STOCK_INFO, N_("Na_me Tab"), NAME_TAB_ACCEL, "Name Tab", G_CALLBACK(terminal_name_tab_activate_event) },
+ { "Tabs_PreviousTab", GTK_STOCK_GO_BACK, N_("Pre_vious Tab"), PREVIOUS_TAB_ACCEL, "Previous Tab", G_CALLBACK(terminal_previous_tab_activate_event) },
+ { "Tabs_NextTab", GTK_STOCK_GO_FORWARD, N_("Ne_xt Tab"), NEXT_TAB_ACCEL, "Next Tab", G_CALLBACK(terminal_next_tab_activate_event) },
+ { "Tabs_MoveTabLeft", NULL, N_("Move Tab _Left"), MOVE_TAB_LEFT_ACCEL, "Move Tab Left", G_CALLBACK(terminal_move_tab_left_activate_event) },
+ { "Tabs_MoveTabRight", NULL, N_("Move Tab _Right"), MOVE_TAB_RIGHT_ACCEL, "Move Tab Right", G_CALLBACK(terminal_move_tab_right_activate_event) },
+ { "Help_About", GTK_STOCK_ABOUT, N_("_About"), NULL, "About", G_CALLBACK(terminal_about_activate_event) }
+};
+#define MENUBAR_MENUITEM_COUNT G_N_ELEMENTS(menu_items)
-static gboolean terminal_window_resize(GtkWidget *widget, GtkRequisition *requisition, LXTerminal *terminal)
+/* Descriptors for popup menu items, accessed via right click on the terminal. */
+static GtkActionEntry vte_menu_items[] =
{
- Term *term;
- GdkGeometry hints;
- gint xpad;
- gint ypad;
- gint i;
-
- if (!terminal->fixedsize) {
- return FALSE;
- }
-
- terminal->fixedsize = FALSE;
-
- /* getting window size by fixed */
- term = g_ptr_array_index(terminal->terms, 0);
- vte_terminal_get_padding(VTE_TERMINAL(term->vte), &xpad, &ypad);
- hints.width_inc = VTE_TERMINAL(term->vte)->char_width;
- hints.height_inc = VTE_TERMINAL(term->vte)->char_height;
- hints.base_width = xpad;
- hints.base_height = ypad;
- hints.min_width = hints.base_width + hints.width_inc * 4;
- hints.min_height = hints.base_height + hints.height_inc * 2;
-
- /* allow resizing by user */
- for (i=0;i<terminal->terms->len;i++) {
- term = g_ptr_array_index(terminal->terms, i);
-
- gtk_window_set_geometry_hints(GTK_WINDOW(terminal->mainw),
- term->vte,
- &hints,
- GDK_HINT_RESIZE_INC
- | GDK_HINT_MIN_SIZE
- | GDK_HINT_BASE_SIZE);
- }
-
- /* setting fixed size */
- gtk_window_resize(GTK_WINDOW(terminal->mainw), requisition->width, requisition->height);
-
- return FALSE;
-}
+ { "VTEMenu", NULL, "VTEMenu" },
+ { "NewWindow", GTK_STOCK_ADD, N_("New _Window"), NULL, "New Window", G_CALLBACK(terminal_new_window_activate_event) },
+ { "NewTab", GTK_STOCK_ADD, N_("New _Tab"), NULL, "New Tab", G_CALLBACK(terminal_new_tab_activate_event) },
+ { "Sep1", NULL, "Sep" },
+ { "Copy", GTK_STOCK_COPY, N_("Cop_y"), NULL, "Copy", G_CALLBACK(terminal_copy_activate_event) },
+ { "Paste", GTK_STOCK_PASTE, N_("_Paste"), NULL, "Paste", G_CALLBACK(terminal_paste_activate_event) },
+ { "Sep2", NULL, "Sep" },
+ { "Preferences", GTK_STOCK_EXECUTE, N_("Preference_s"), NULL, "Preferences", G_CALLBACK(terminal_preferences_dialog) },
+ { "Sep3", NULL, "Sep" },
+ { "NameTab", GTK_STOCK_INFO, N_("Na_me Tab"), NULL, "Name Tab", G_CALLBACK(terminal_name_tab_activate_event) },
+ { "PreviousTab", GTK_STOCK_GO_BACK, N_("Pre_vious Tab"), NULL, "Previous Tab", G_CALLBACK(terminal_previous_tab_activate_event) },
+ { "NextTab", GTK_STOCK_GO_FORWARD, N_("Ne_xt Tab"), NULL, "Next Tab", G_CALLBACK(terminal_next_tab_activate_event) },
+ { "Tabs_MoveTabLeft", NULL, N_("Move Tab _Left"), NULL, "Move Tab Left", G_CALLBACK(terminal_move_tab_left_activate_event) },
+ { "Tabs_MoveTabRight", NULL, N_("Move Tab _Right"), NULL, "Move Tab Right", G_CALLBACK(terminal_move_tab_right_activate_event) },
+ { "CloseTab", GTK_STOCK_CLOSE, N_("_Close Tab"), NULL, "Close Tab", G_CALLBACK(terminal_close_tab_activate_event) }
+};
+#define VTE_MENUITEM_COUNT G_N_ELEMENTS(vte_menu_items)
-static void terminal_window_set_fixed_size(LXTerminal *terminal)
+/* Copied out of static function in gdk_window.
+ * A wrapper around XGetWMNormalHints. */
+static void gdk_window_get_geometry_hints(GdkWindow * window, GdkGeometry * geometry, GdkWindowHints * geometry_mask)
{
- Term *term;
- gint i;
+ g_return_if_fail(GDK_IS_WINDOW (window));
+ g_return_if_fail(geometry != NULL);
+ g_return_if_fail(geometry_mask != NULL);
- terminal->fixedsize = TRUE;
+ *geometry_mask = 0;
- for (i=0;i<terminal->terms->len;i++) {
- term = g_ptr_array_index(terminal->terms, i);
+ if (GDK_WINDOW_DESTROYED(window))
+ return;
- gtk_window_set_geometry_hints(GTK_WINDOW(terminal->mainw),
- term->vte,
- &terminal->geometry,
- terminal->geom_mask);
- }
-}
+ XSizeHints size_hints;
+ glong junk_size_mask = 0;
+ if ( ! XGetWMNormalHints(GDK_WINDOW_XDISPLAY(window), GDK_WINDOW_XID(window), &size_hints, &junk_size_mask))
+ return;
-static gboolean term_switchtab(Term *term)
-{
- LXTerminal *terminal = term->parent;
- gtk_notebook_set_current_page(GTK_NOTEBOOK(terminal->notebook), term->index);
- return TRUE;
-}
+ if (size_hints.flags & PMinSize)
+ {
+ *geometry_mask |= GDK_HINT_MIN_SIZE;
+ geometry->min_width = size_hints.min_width;
+ geometry->min_height = size_hints.min_height;
+ }
-static gboolean terminal_copy(GtkAction *action, gpointer data)
-{
- LXTerminal *terminal = (LXTerminal *)data;
- Term *term;
+ if (size_hints.flags & PMaxSize)
+ {
+ *geometry_mask |= GDK_HINT_MAX_SIZE;
+ geometry->max_width = MAX (size_hints.max_width, 1);
+ geometry->max_height = MAX (size_hints.max_height, 1);
+ }
- /* getting current vte */
- term = g_ptr_array_index(terminal->terms, gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook)));
+ if (size_hints.flags & PResizeInc)
+ {
+ *geometry_mask |= GDK_HINT_RESIZE_INC;
+ geometry->width_inc = size_hints.width_inc;
+ geometry->height_inc = size_hints.height_inc;
+ }
- /* copy from vte */
- vte_terminal_copy_clipboard(VTE_TERMINAL(term->vte));
+ if (size_hints.flags & PAspect)
+ {
+ *geometry_mask |= GDK_HINT_ASPECT;
+ geometry->min_aspect = (gdouble) size_hints.min_aspect.x / (gdouble) size_hints.min_aspect.y;
+ geometry->max_aspect = (gdouble) size_hints.max_aspect.x / (gdouble) size_hints.max_aspect.y;
+ }
- return TRUE;
+ if (size_hints.flags & PWinGravity)
+ {
+ *geometry_mask |= GDK_HINT_WIN_GRAVITY;
+ geometry->win_gravity = size_hints.win_gravity;
+ }
}
-static gboolean terminal_copy_accel(gpointer data, guint action, GtkWidget *item)
+/* Accessor for border values from VteTerminal. */
+static GtkBorder * terminal_get_border(Term * term)
{
- return terminal_copy(NULL, data);
+#if VTE_CHECK_VERSION(0, 24, 0)
+ /* Style property, new in 0.24.0, replaces the function below. */
+ GtkBorder * border;
+ gtk_widget_style_get(term->vte, "inner-border", &border, NULL);
+ return gtk_border_copy(border);
+#else
+ /* Deprecated function produces a warning. */
+ GtkBorder * border = gtk_border_new();
+ vte_terminal_get_padding(VTE_TERMINAL(term->vte), &border->left, &border->top);
+ return border;
+#endif
}
-static gboolean terminal_paste(GtkAction *action, gpointer data)
+/* Restore the terminal geometry after a font size change or hiding the tab bar. */
+static void terminal_geometry_restore(Term * term)
{
- LXTerminal *terminal = (LXTerminal *)data;
- Term *term;
-
- /* getting current vte */
- term = g_ptr_array_index(terminal->terms, gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook)));
-
- /* copy from vte */
- vte_terminal_paste_clipboard(VTE_TERMINAL(term->vte));
+ /* Set fixed VTE size. */
+ terminal_window_set_fixed_size(term->parent);
+
+ /* Recover the window size. */
+ GtkBorder * border = terminal_get_border(term);
+ vte_terminal_set_size(VTE_TERMINAL(term->vte),
+ vte_terminal_get_column_count(VTE_TERMINAL(term->vte)),
+ vte_terminal_get_row_count(VTE_TERMINAL(term->vte)));
+ gtk_window_resize(GTK_WINDOW(term->parent->window),
+ border->left + VTE_TERMINAL(term->vte)->char_width,
+ border->top + VTE_TERMINAL(term->vte)->char_height);
+ gtk_border_free(border);
+}
- return TRUE;
+/* Set the position of the tabs on the main window. */
+static void terminal_tab_set_position(GtkWidget * notebook, gint tab_position)
+{
+ switch (tab_position)
+ {
+ case 0:
+ gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
+ break;
+ case 1:
+ gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM);
+ break;
+ case 2:
+ gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
+ break;
+ default:
+ gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_RIGHT);
+ break;
+ }
}
-static gboolean terminal_paste_accel(gpointer data, guint action, GtkWidget *item)
+/* Initialize the <ALT> n accelerators, where n is a digit.
+ * These switch to the tab selected by the digit, if it exists. */
+static void terminal_initialize_switch_tab_accelerator(Term * term)
{
- return terminal_paste(NULL, data);
+ if ((term->index + 1) < 10)
+ {
+ /* Formulate the accelerator name. */
+ char switch_tab_accel[1 + 3 + 1 + 1 + 1]; /* "<ALT>n" */
+ sprintf(switch_tab_accel, "<ALT>%d", term->index + 1);
+
+ /* Parse the accelerator name. */
+ guint key;
+ GdkModifierType mods;
+ gtk_accelerator_parse(switch_tab_accel, &key, &mods);
+
+ /* Define the accelerator. */
+ term->closure = g_cclosure_new_swap(G_CALLBACK(terminal_switch_tab_accelerator), term, NULL);
+ gtk_accel_group_connect(term->parent->accel_group, key, mods, GTK_ACCEL_LOCKED, term->closure);
+ }
}
-static void terminal_nexttab(GtkAction *action, gpointer data)
+/* Handler for accelerator <ALT> n, where n is a digit.
+ * Switch to the tab selected by the digit, if it exists. */
+static void terminal_switch_tab_accelerator(Term * term)
{
- LXTerminal *terminal = (LXTerminal *)data;
+ LXTerminal * terminal = term->parent;
+ if (term->index < gtk_notebook_get_n_pages(GTK_NOTEBOOK(terminal->notebook)))
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(terminal->notebook), term->index);
+}
- /* cycle */
- if (gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook))==gtk_notebook_get_n_pages(GTK_NOTEBOOK(terminal->notebook))-1)
- gtk_notebook_set_current_page(GTK_NOTEBOOK(terminal->notebook), 0);
- else
- gtk_notebook_next_page(GTK_NOTEBOOK(terminal->notebook));
+/* Handler for "activate" signal on File/New Window menu item.
+ * Open a new window. */
+static void terminal_new_window_activate_event(GtkAction * action, LXTerminal * terminal)
+{
+ CommandArguments arguments;
+ memset(&arguments, 0, sizeof(arguments));
+ lxterminal_initialize(terminal->parent, &arguments, terminal->setting);
}
-static void terminal_nexttab_accel(gpointer data, guint action, GtkWidget *item)
+/* Handler for accelerator <SHIFT><CTRL> N. Open a new window. */
+static void terminal_new_window_accelerator(LXTerminal * terminal, guint action, GtkWidget * item)
{
- terminal_nexttab(NULL, data);
+ terminal_new_window_activate_event(NULL, terminal);
}
-static void terminal_prevtab(GtkAction *action, gpointer data)
+/* Handler for "activate" signal on File/New Tab menu item.
+ * Open a new tab. */
+static void terminal_new_tab_activate_event(GtkAction * action, LXTerminal * terminal)
{
- LXTerminal *terminal = (LXTerminal *)data;
+ gchar * proc_cwd = NULL;
+
+#ifdef __linux
+ /* Try to get the working directory from /proc. */
+ gint current = gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook));
+ if (current != -1)
+ {
+ /* Search for the Term structure corresponding to the current tab. */
+ int i;
+ for (i = 0; i < terminal->terms->len; i += 1)
+ {
+ Term * term = g_ptr_array_index(terminal->terms, i);
+ if (term->index == current)
+ {
+ /* Get the working directory corresponding to the process ID. */
+ gchar proc_cwd_link[PATH_MAX];
+ g_snprintf(proc_cwd_link, PATH_MAX, "/proc/%d/cwd", term->pid);
+ proc_cwd = g_file_read_link(proc_cwd_link, NULL);
+ break;
+ }
+ }
+
+ }
+#endif
- /* cycle */
- if (gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook))==0)
- gtk_notebook_set_current_page(GTK_NOTEBOOK(terminal->notebook), -1);
- else
- gtk_notebook_prev_page(GTK_NOTEBOOK(terminal->notebook));
+ /* Propagate the working directory of the current tab to the new tab.
+ * If the working directory was determined above, use it; otherwise default to the working directory of the process.
+ * Create the new terminal. */
+ if (proc_cwd == NULL)
+ proc_cwd = g_get_current_dir();
+ Term * term = terminal_new(terminal, _("LXTerminal"), proc_cwd, NULL, NULL);
+ g_free(proc_cwd);
+
+ /* Add a tab to the notebook and the "terms" array. */
+ gtk_notebook_append_page(GTK_NOTEBOOK(terminal->notebook), term->box, term->tab);
+ term->index = gtk_notebook_get_n_pages(GTK_NOTEBOOK(terminal->notebook)) - 1;
+ g_ptr_array_add(terminal->terms, term);
+
+ /* Redraw the terminal. */
+ gtk_widget_queue_draw(term->vte);
+
+ /* Make the new terminal's tab current and, if we went from one to more than one tab,
+ * turn the tab display on. */
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(term->parent->notebook), term->index);
+ if (term->index > 0)
+ {
+ terminal_window_set_fixed_size(terminal);
+ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(term->parent->notebook), TRUE);
+ }
+ terminal_initialize_switch_tab_accelerator(term);
}
-static void terminal_prevtab_accel(gpointer data, guint action, GtkWidget *item)
+/* Handler for accelerator <SHIFT><CTRL> T. Open a new tab. */
+static void terminal_new_tab_accelerator(LXTerminal * terminal, guint action, GtkWidget * item)
{
- terminal_prevtab(NULL, data);
+ terminal_new_tab_activate_event(NULL, terminal);
}
-/* direction: -1=left 1=right */
-static void terminal_movetab(GtkAction *action, gpointer data, gint direction)
+/* Handler for "activate" signal on File/Close Tab menu item.
+ * Close the current tab. */
+static void terminal_close_tab_activate_event(GtkAction * action, LXTerminal * terminal)
{
- LXTerminal *terminal = (LXTerminal *)data;
- GtkNotebook *notebook = GTK_NOTEBOOK(terminal->notebook);
- gint curPageNum = gtk_notebook_get_current_page( notebook );
-
- gtk_notebook_reorder_child(
- notebook,
- gtk_notebook_get_nth_page(notebook, curPageNum),
- curPageNum + direction
- );
+ Term * term = g_ptr_array_index(terminal->terms, gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook)));
+ terminal_child_exited_event(VTE_TERMINAL(term->vte), term);
}
-static void terminal_movetableft(GtkAction *action, gpointer data)
+/* Handler for accelerator <SHIFT><CTRL> W. Close the current tab. */
+static void terminal_close_tab_accelerator(LXTerminal * terminal, guint action, GtkWidget * item)
{
- terminal_movetab(action, data, -1);
+ terminal_close_tab_activate_event(NULL, terminal);
}
-static void terminal_movetableft_accel(gpointer data, guint action, GtkWidget *item)
+/* Handler for "activate" signal on Edit/Copy menu item.
+ * Copy to the clipboard. */
+static void terminal_copy_activate_event(GtkAction * action, LXTerminal * terminal)
{
- terminal_movetableft(NULL, data);
+ Term * term = g_ptr_array_index(terminal->terms, gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook)));
+ vte_terminal_copy_clipboard(VTE_TERMINAL(term->vte));
}
-static void terminal_movetabright(GtkAction *action, gpointer data)
+/* Handler for accelerator <CTRL><SHIFT> C. Copy to the clipboard. */
+static void terminal_copy_accelerator(LXTerminal * terminal, guint action, GtkWidget * item)
{
- terminal_movetab(action, data, 1);
+ terminal_copy_activate_event(NULL, terminal);
}
-static void terminal_movetabright_accel(gpointer data, guint action, GtkWidget *item)
+/* Handler for "activate" signal on Edit/Paste menu item.
+ * Paste from the clipboard. */
+static void terminal_paste_activate_event(GtkAction * action, LXTerminal * terminal)
{
- terminal_movetabright(NULL, data);
+ Term * term = g_ptr_array_index(terminal->terms, gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook)));
+ vte_terminal_paste_clipboard(VTE_TERMINAL(term->vte));
}
-static void terminal_closetab(GtkAction *action, gpointer data)
+/* Handler for accelerator <CTRL><SHIFT> V. Paste from the clipboard. */
+static void terminal_paste_accelerator(LXTerminal * terminal, guint action, GtkWidget * item)
{
- LXTerminal *terminal = (LXTerminal *)data;
- Term *term;
-
- /* getting current vte */
- term = g_ptr_array_index(terminal->terms, gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook)));
-
- /* release child */
- terminal_childexit(VTE_TERMINAL(term->vte), term);
+ terminal_paste_activate_event(NULL, terminal);
}
-static void terminal_closetab_accel(gpointer data, guint action, GtkWidget *item)
+/* Handler for "response" signal on Name Tab dialog. */
+static void terminal_name_tab_response_event(GtkWidget * dialog, gint response, LXTerminal * terminal)
{
- terminal_closetab(NULL, data);
+ if (response == GTK_RESPONSE_OK)
+ {
+ GtkWidget * dialog_item = g_object_get_data(G_OBJECT(dialog), "entry");
+
+ gint current = gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook));
+ if (current != -1)
+ {
+ /* Search for the Term structure corresponding to the current tab. */
+ int i;
+ for (i = 0; i < terminal->terms->len; i += 1)
+ {
+ Term * term = g_ptr_array_index(terminal->terms, i);
+ if (term->index == current)
+ {
+ /* If Term structure found, set the tab's label and mark it so we will never overwrite it. */
+ term->user_specified_label = TRUE;
+ gtk_label_set_text(GTK_LABEL(term->label), g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog_item))));
+ break;
+ }
+ }
+ }
+ }
+
+ /* Dismiss dialog. */
+ gtk_widget_destroy(dialog);
}
-static void terminal_newwindow(GtkAction *action, gpointer data)
+/* Handler for "activate" signal on Tabs/Name Tab menu item.
+ * Put up a dialog to get a user specified name for the tab. */
+static void terminal_name_tab_activate_event(GtkAction * action, LXTerminal * terminal)
{
- LXTerminal *terminal = (LXTerminal *)data;
-
- lxterminal_init(terminal->parent, 0, NULL, terminal->setting);
+ GtkWidget * dialog = gtk_dialog_new_with_buttons(
+ _("Name Tab"),
+ GTK_WINDOW(terminal->window),
+ 0,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL);
+ gtk_window_set_icon_from_file(GTK_WINDOW(dialog), PACKAGE_DATA_DIR "/pixmaps/lxterminal.png", NULL);
+ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(terminal_name_tab_response_event), terminal);
+ GtkWidget * dialog_item = gtk_entry_new();
+ g_object_set_data(G_OBJECT(dialog), "entry", (gpointer) dialog_item);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), dialog_item, FALSE, FALSE, 2);
+ gint current = gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook));
+ if (current != -1)
+ {
+ /* Search for the Term structure corresponding to the current tab. */
+ int i;
+ for (i = 0; i < terminal->terms->len; i += 1)
+ {
+ Term * term = g_ptr_array_index(terminal->terms, i);
+ if (term->index == current)
+ {
+ gtk_entry_set_text(GTK_ENTRY(dialog_item), gtk_label_get_text(GTK_LABEL(term->label)));
+ break;
+ }
+ }
+ }
+ gtk_widget_show_all(dialog);
}
-static void terminal_newwindow_accel(gpointer data, guint action, GtkWidget *item)
+/* Handler for accelerator <CTRL><SHIFT> R. Name the tab. */
+static void terminal_name_tab_accelerator(LXTerminal * terminal, guint action, GtkWidget * item)
{
- terminal_newwindow(NULL, data);
+ terminal_name_tab_activate_event(NULL, terminal);
}
-static void term_set_swicth_accel(Term *term)
+/* Handler for "activate" signal on Tabs/Previous Tab menu item.
+ * Cycle through tabs in the reverse direction. */
+static void terminal_previous_tab_activate_event(GtkAction * action, LXTerminal * terminal)
{
- if (term->index + 1 < 10) {
- char switch_tab_accel[1 + 3 + 1 + 1 + 1]; /* "<ALT>n" */
- guint key;
- GdkModifierType mods;
- GtkAccelGroup *accel_group = term->parent->menubar->accel_group;
-
- sprintf(switch_tab_accel, "<ALT>%d", term->index + 1);
- gtk_accelerator_parse(switch_tab_accel, &key, &mods);
- term->closure = g_cclosure_new_swap(G_CALLBACK(term_switchtab), term, NULL);
- gtk_accel_group_connect(accel_group, key, mods, GTK_ACCEL_LOCKED,
- term->closure);
- }
+ /* Cycle through tabs. */
+ if (gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook)) == 0)
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(terminal->notebook), -1);
+ else
+ gtk_notebook_prev_page(GTK_NOTEBOOK(terminal->notebook));
}
-static void terminal_newtab(GtkWidget *widget, gpointer data)
+/* Handler for accelerator <CTRL><PAGE UP>. Cycle through tabs in the reverse direction. */
+static void terminal_previous_tab_accelerator(LXTerminal * terminal, guint action, GtkWidget * item)
{
- LXTerminal *terminal = (LXTerminal *)data;
- Term *term;
-
-#ifdef __linux
- gchar cwd[PATH_MAX];
-
- gint current = gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook));
- if (current != -1) {
- gchar proc_cwd_link[PATH_MAX];
- gchar *proc_cwd;
- gint i;
- for (i=0;i<terminal->terms->len;i++) {
- term = g_ptr_array_index(terminal->terms, i);
- if (term->index == current)
- break;
- }
-
- g_message("%d", term->pid);
- g_snprintf(proc_cwd_link, PATH_MAX, "/proc/%d/cwd", term->pid);
- proc_cwd = g_file_read_link(proc_cwd_link, NULL);
- if (proc_cwd) {
- g_strlcpy(cwd, proc_cwd, PATH_MAX);
- g_free(proc_cwd);
- } else {
- g_strlcpy(cwd, g_get_current_dir(), PATH_MAX);
- }
- } else {
- g_strlcpy(cwd, g_get_current_dir(), PATH_MAX);
- }
-
- term = terminal_new(terminal, _("LXTerminal"), cwd, NULL, NULL);
-#else
- term = terminal_new(terminal, _("LXTerminal"), g_get_current_dir(), NULL, NULL);
-#endif
+ terminal_previous_tab_activate_event(NULL, terminal);
+}
- /* add page to notebook */
- gtk_notebook_append_page(GTK_NOTEBOOK(terminal->notebook), term->box, term->label->main);
- term->index = gtk_notebook_get_n_pages(GTK_NOTEBOOK(terminal->notebook)) - 1;
- g_ptr_array_add(terminal->terms, term);
+/* Handler for "activate" signal on Tabs/Next Tab menu item.
+ * Cycle through tabs in the forward direction. */
+static void terminal_next_tab_activate_event(GtkAction * action, LXTerminal * terminal)
+{
+ /* Cycle through tabs. */
+ if (gtk_notebook_get_current_page(GTK_NOTEBOOK(terminal->notebook)) == gtk_notebook_get_n_pages(GTK_NOTEBOOK(terminal->notebook)) - 1)
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(terminal->notebook), 0);
+ else
+ gtk_notebook_next_page(GTK_NOTEBOOK(terminal->notebook));
+}
- /* push VTE to queue */
- gtk_widget_queue_draw(term->vte);
+/* Handler for accelerator <CTRL><PAGE DOWN>. Cycle through tabs in the forward direction. */
+static void terminal_next_tab_accelerator(LXTerminal * terminal, guint action, GtkWidget * item)
+{
+ terminal_next_tab_activate_event(NULL, terminal);
+}
- gtk_notebook_set_current_page(GTK_NOTEBOOK(term->parent->notebook), term->index);
+/* Helper for move tab left and right. */
+static void terminal_move_tab_execute(LXTerminal * terminal, gint direction)
+{
+ GtkNotebook * notebook = GTK_NOTEBOOK(terminal->notebook);
+ gint current_page_number = gtk_notebook_get_current_page(notebook);
+ gtk_notebook_reorder_child(notebook, gtk_notebook_get_nth_page(notebook, current_page_number), current_page_number + direction);
+}
- if (term->index > 0) {
- /* fixed VTE size */
- terminal_window_set_fixed_size(terminal);
+/* Handler for "activate" signal on Tabs/Move Tab Left menu item.
+ * Move the tab one position in the reverse direction. */
+static void terminal_move_tab_left_activate_event(GtkAction * action, LXTerminal * terminal)
+{
+ terminal_move_tab_execute(terminal, -1);
+}
- /* show tab */
- gtk_notebook_set_show_tabs(GTK_NOTEBOOK(term->parent->notebook), TRUE);
- }
- term_set_swicth_accel(term);
+/* Handler for accelerator <SHIFT><CTRL><PAGE UP>. Move the tab one position in the reverse direction. */
+static void terminal_move_tab_left_accelerator(LXTerminal * terminal, guint action, GtkWidget * item)
+{
+ terminal_move_tab_execute(terminal, -1);
}
-static void terminal_newtab_accel(gpointer data, guint action, GtkWidget *item)
+/* Handler for "activate" signal on Tabs/Move Tab Right menu item.
+ * Move the tab one position in the forward direction. */
+static void terminal_move_tab_right_activate_event(GtkAction * action, LXTerminal * terminal)
{
- terminal_newtab(NULL, data);
+ terminal_move_tab_execute(terminal, 1);
}
-static void open_url( GtkAboutDialog* dlg, const gchar* url, gpointer data )
+/* Handler for accelerator <SHIFT><CTRL><PAGE DOWN>. Move the tab one position in the forward direction. */
+static void terminal_move_tab_right_accelerator(LXTerminal * terminal, guint action, GtkWidget * item)
{
- /* FIXME: */
+ terminal_move_tab_execute(terminal, 1);
}
-static void terminal_about(GtkAction *action, gpointer data)
+/* Handler for "activate" signal on Help/About menu item. */
+static void terminal_about_activate_event(GtkAction * action, LXTerminal * terminal)
{
- GtkWidget * about_dlg;
- const gchar *authors[] =
+ const gchar * authors[] =
{
"Fred Chien <cfsghost@gmail.com>",
+ "Marty Jack <martyj19@comcast.net>",
NULL
};
/* TRANSLATORS: Replace this string with your names, one name per line. */
- gchar *translators = _( "translator-credits" );
-
- gtk_about_dialog_set_url_hook( open_url, NULL, NULL);
-
- about_dlg = gtk_about_dialog_new ();
-
- gtk_container_set_border_width ( ( GtkContainer*)about_dlg , 2 );
- gtk_about_dialog_set_version ( (GtkAboutDialog*)about_dlg, VERSION );
- gtk_about_dialog_set_name ( (GtkAboutDialog*)about_dlg, _( "LXTerminal" ) );
- gtk_about_dialog_set_logo( (GtkAboutDialog*)about_dlg, gdk_pixbuf_new_from_file( PACKAGE_DATA_DIR"/pixmaps/lxterminal.png", NULL ) );
- gtk_about_dialog_set_copyright ( (GtkAboutDialog*)about_dlg, _( "Copyright (C) 2008" ) );
- gtk_about_dialog_set_comments ( (GtkAboutDialog*)about_dlg, _( "Terminal emulator for LXDE project" ) );
- gtk_about_dialog_set_license ( (GtkAboutDialog*)about_dlg, "This program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA." );
- gtk_about_dialog_set_website ( (GtkAboutDialog*)about_dlg, "http://lxde.org/" );
- gtk_about_dialog_set_authors ( (GtkAboutDialog*)about_dlg, authors );
- gtk_about_dialog_set_translator_credits ( (GtkAboutDialog*)about_dlg, translators );
-
- gtk_dialog_run( ( GtkDialog*)about_dlg );
- gtk_widget_destroy( about_dlg );
+ gchar * translators = _("translator-credits");
+
+ /* Create and initialize the dialog. */
+ GtkWidget * about_dlg = gtk_about_dialog_new();
+ gtk_about_dialog_set_url_hook(NULL, NULL, NULL);
+ gtk_container_set_border_width(GTK_CONTAINER(about_dlg), 2);
+ gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about_dlg), VERSION);
+ gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about_dlg), _("LXTerminal"));
+ gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about_dlg), gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/pixmaps/lxterminal.png", NULL));
+ gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about_dlg), _("Copyright (C) 2008-2010"));
+ gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about_dlg), _("Terminal emulator for LXDE project"));
+ gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about_dlg), "This program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.");
+ gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about_dlg), "http://lxde.org/");
+ gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about_dlg), authors);
+ gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about_dlg), translators);
+
+ /* Display the dialog, wait for the user to click OK, and dismiss the dialog. */
+ gtk_dialog_run(GTK_DIALOG(about_dlg));
+ gtk_widget_destroy(about_dlg);
}
-static GtkActionEntry menu_items[] =
+/* Handler for "size-request" signal on the top level window. */
+static gboolean terminal_window_size_request_event(GtkWidget * widget, GtkRequisition * requisition, LXTerminal * terminal)
{
- { "File_NewWindow", GTK_STOCK_ADD, N_("New _Window"), NEW_WINDOW_ACCEL, "New Window", G_CALLBACK(terminal_newwindow)},
- { "File_NewTab", GTK_STOCK_ADD, N_("New _Tab"), NEW_TAB_ACCEL, "New Tab", G_CALLBACK(terminal_newtab)},
- { "File_Sep1", NULL, "Sep" },
- { "File_CloseTab", GTK_STOCK_CLOSE, N_("_Close Tab"), CLOSE_TAB_ACCEL, "Close Tab", G_CALLBACK(terminal_closetab)},
- { "File_Quit", GTK_STOCK_QUIT, N_("_Quit"), QUIT_ACCEL, "Quit", G_CALLBACK(gtk_main_quit)},
- { "Edit_Copy", GTK_STOCK_COPY, N_("Cop_y"), COPY_ACCEL, "Copy", G_CALLBACK(terminal_copy)},
- { "Edit_Paste", GTK_STOCK_PASTE, N_("_Paste"), PASTE_ACCEL, "Paste", G_CALLBACK(terminal_paste)},
- { "Edit_Sep1", NULL, "Sep" },
- { "Edit_Preferences", GTK_STOCK_EXECUTE, N_("Preference_s"), NULL, "Preferences", G_CALLBACK(lxterminal_preferences_dialog)},
-// { "View_CharacterEncoding", NULL, N_("_Character Encoding"), NULL, "Character Encoding", NULL},
- { "Tabs_PreviousTab", GTK_STOCK_GO_BACK, N_("Pre_vious Tab"), PREVIOUS_TAB_ACCEL, "Previous Tab", G_CALLBACK(terminal_prevtab)},
- { "Tabs_NextTab", GTK_STOCK_GO_FORWARD, N_("Ne_xt Tab"), NEXT_TAB_ACCEL, "Next Tab", G_CALLBACK(terminal_nexttab)},
- { "Tabs_MoveTabLeft", NULL, N_("Move Tab _Left"), MOVE_TAB_LEFT_ACCEL, "Move Tab Left", G_CALLBACK(terminal_movetableft)},
- { "Tabs_MoveTabRight", NULL, N_("Move Tab _Right"), MOVE_TAB_RIGHT_ACCEL, "Move Tab Right", G_CALLBACK(terminal_movetabright)},
- { "Help_About", GTK_STOCK_ABOUT, N_("_About"), NULL, "About", G_CALLBACK(terminal_about)}
-};
-#define MENUBAR_MENUITEM_COUNT G_N_ELEMENTS(menu_items)
+ /* Only do this once. */
+ if (terminal->fixed_size)
+ {
+ /* No longer fixed size. */
+ terminal->fixed_size = FALSE;
+
+ /* Initialize geometry hints structure. */
+ Term * term = g_ptr_array_index(terminal->terms, 0);
+ GtkBorder * border = terminal_get_border(term);
+ GdkGeometry hints;
+ hints.width_inc = VTE_TERMINAL(term->vte)->char_width;
+ hints.height_inc = VTE_TERMINAL(term->vte)->char_height;
+ hints.base_width = border->left;
+ hints.base_height = border->top;
+ hints.min_width = hints.base_width + hints.width_inc * 4;
+ hints.min_height = hints.base_height + hints.height_inc * 2;
+ gtk_border_free(border);
+
+ /* Set hints into all terminals. This makes sure we resize on character cell boundaries. */
+ int i;
+ for (i = 0; i < terminal->terms->len; i += 1)
+ {
+ Term * term = g_ptr_array_index(terminal->terms, i);
+ gtk_window_set_geometry_hints(GTK_WINDOW(terminal->window),
+ term->vte,
+ &hints,
+ GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE);
+ }
+
+ /* Resize the window. */
+ gtk_window_resize(GTK_WINDOW(terminal->window), requisition->width, requisition->height);
+ }
+ return FALSE;
+}
-static GtkActionEntry vte_menu_items[] =
+/* Set geometry hints for the fixed size case. */
+static void terminal_window_set_fixed_size(LXTerminal * terminal)
{
- { "VTEMenu", NULL, "VTEMenu" },
- { "NewWindow", GTK_STOCK_ADD, N_("New _Window"), NULL, "New Window", G_CALLBACK(terminal_newwindow)},
- { "NewTab", GTK_STOCK_ADD, N_("New _Tab"), NULL, "New Tab", G_CALLBACK(terminal_newtab)},
- { "Sep1", NULL, "Sep" },
- { "Copy", GTK_STOCK_COPY, N_("Cop_y"), NULL, "Copy", G_CALLBACK(terminal_copy)},
- { "Paste", GTK_STOCK_PASTE, N_("_Paste"), NULL, "Paste", G_CALLBACK(terminal_paste)},
- { "Sep2", NULL, "Sep" },
- { "Preferences", GTK_STOCK_EXECUTE, N_("Preference_s"), NULL, "Preferences", G_CALLBACK(lxterminal_preferences_dialog)},
- { "Sep3", NULL, "Sep" },
- { "PreviousTab", GTK_STOCK_GO_BACK, N_("Pre_vious Tab"), NULL, "Previous Tab", G_CALLBACK(terminal_prevtab)},
- { "NextTab", GTK_STOCK_GO_FORWARD, N_("Ne_xt Tab"), NULL, "Next Tab", G_CALLBACK(terminal_nexttab)},
- { "Tabs_MoveTabLeft", NULL, N_("Move Tab _Left"), NULL, "Move Tab Left", G_CALLBACK(terminal_prevtab)},
- { "Tabs_MoveTabRight", NULL, N_("Move Tab _Right"), NULL, "Move Tab Right", G_CALLBACK(terminal_nexttab)},
- { "CloseTab", GTK_STOCK_CLOSE, N_("_Close Tab"), NULL, "Close Tab", G_CALLBACK(terminal_closetab)}
-};
-#define VTE_MENUITEM_COUNT G_N_ELEMENTS(vte_menu_items)
+ terminal->fixed_size = TRUE;
+ int i;
+ for (i = 0; i < terminal->terms->len; i += 1)
+ {
+ Term * term = g_ptr_array_index(terminal->terms, i);
+ gtk_window_set_geometry_hints(GTK_WINDOW(terminal->window),
+ term->vte,
+ &terminal->geometry,
+ terminal->geometry_mask);
+ }
+}
-static void terminal_switch_tab(GtkNotebook *notebook, GtkNotebookPage *page, guint num, gpointer data)
+/* Handler for "switch-page" event on the tab notebook. */
+static void terminal_switch_page_event(GtkNotebook * notebook, GtkNotebookPage * page, guint num, LXTerminal * terminal)
{
- const gchar *title;
- Term *term;
- LXTerminal *terminal = (LXTerminal *)data;
-
- if (terminal->terms->len <= num)
- return;
-
- term = g_ptr_array_index(terminal->terms, num);
-
- /* if title of VTE is NULL */
- if ((title = vte_terminal_get_window_title(VTE_TERMINAL(term->vte))) == NULL)
- gtk_window_set_title(GTK_WINDOW(terminal->mainw), _("LXTerminal"));
- else
- gtk_window_set_title(GTK_WINDOW(terminal->mainw), title);
+ if (terminal->terms->len > num)
+ {
+ /* Propagate the title to the toplevel window. */
+ Term * term = g_ptr_array_index(terminal->terms, num);
+ const gchar * title = vte_terminal_get_window_title(VTE_TERMINAL(term->vte));
+ gtk_window_set_title(GTK_WINDOW(terminal->window), ((title != NULL) ? title : _("LXTerminal")));
+ }
}
-static void terminal_title_changed(VteTerminal *vte, Term *term)
+/* Handler for "window-title-changed" signal on a Term. */
+static void terminal_window_title_changed_event(GtkWidget * vte, Term * term)
{
- /* setting label */
- lxterminal_tab_label_set_text(term->label, vte_terminal_get_window_title(VTE_TERMINAL(vte)));
- lxterminal_tab_label_set_tooltip_text(term->label, vte_terminal_get_window_title(VTE_TERMINAL(vte)));
-
- /* setting window title */
- gtk_window_set_title(GTK_WINDOW(term->parent->mainw), vte_terminal_get_window_title(VTE_TERMINAL(vte)));
+ /* Copy the VTE data out into the tab and the window title, unless the user edited the tab label. */
+ if ( ! term->user_specified_label)
+ {
+ gtk_label_set_text(GTK_LABEL(term->label), vte_terminal_get_window_title(VTE_TERMINAL(vte)));
+ gtk_widget_set_tooltip_text(term->label, vte_terminal_get_window_title(VTE_TERMINAL(vte)));
+ }
+ gtk_window_set_title(GTK_WINDOW(term->parent->window), vte_terminal_get_window_title(VTE_TERMINAL(vte)));
}
-static void terminal_windowexit(gpointer terminal_p, GObject *where_the_object_was)
+/* Weak-notify callback for LXTerminal object. */
+static void terminal_window_exit(LXTerminal * terminal, GObject * where_the_object_was)
{
- LXTerminal * terminal = (LXTerminal *) terminal_p;
+ /* If last window, exit main loop. */
+ if (terminal->parent->windows->len == 1)
+ gtk_main_quit();
+
+ else
+ {
+ /* Remove the element and decrease the index number of each succeeding element. */
+ g_ptr_array_remove_index(terminal->parent->windows, terminal->index);
int i;
+ for (i = terminal->index; i < terminal->parent->windows->len; i += 1)
+ {
+ LXTerminal * t = g_ptr_array_index(terminal->parent->windows, i);
+ t->index -= 1;
+ }
+ }
+}
- if (terminal->parent->windows->len==1) {
- gtk_main_quit();
- } else {
- g_ptr_array_remove_index(terminal->parent->windows, terminal->index);
+/* Handler for "child-exited" signal on VTE.
+ * Also handler for "activate" signal on Close button of tab and File/Close Tab menu item and accelerator. */
+static void terminal_child_exited_event(VteTerminal * vte, Term * term)
+{
+ LXTerminal * terminal = term->parent;
- /* decreasing index number after the window be removed */
- for (i=terminal->index;i<terminal->parent->windows->len;i++) {
- LXTerminal *t = g_ptr_array_index(terminal->parent->windows, i);
- t->index--;
- }
+ /* Last tab being deleted. Deallocate memory and close the window. */
+ if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(terminal->notebook)) == 1)
+ {
+ g_ptr_array_free(terminal->terms, TRUE);
+ gtk_widget_destroy(terminal->window);
+ }
- }
+ /* Not last tab being deleted. */
+ else
+ {
+ /* Remove the element and decrease the index number of each succeeding element. */
+ g_ptr_array_remove_index(terminal->terms, term->index);
+ int i;
+ for (i = term->index; i < terminal->terms->len; i++)
+ {
+ Term * t = g_ptr_array_index(terminal->terms, i);
+ t->index -= 1;
+ }
+
+ /* Delete the tab and free the Term structure. */
+ gtk_notebook_remove_page(GTK_NOTEBOOK(terminal->notebook), term->index);
+ terminal_free(term);
+
+ /* If only one page is left, hide the tab and correct the geometry. */
+ if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(terminal->notebook)) == 1)
+ {
+ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(terminal->notebook), FALSE);
+ terminal_geometry_restore(g_ptr_array_index(terminal->terms, 0));
+ }
+ }
}
-static void terminal_childexit(VteTerminal *vte, Term *term)
+/* Handler for "button-press-event" signal on a notebook tab. */
+static gboolean terminal_tab_button_press_event(GtkWidget * widget, GdkEventButton * event, Term * term)
{
- int i;
- LXTerminal *terminal = term->parent;
-
- if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(terminal->notebook))==1) {
- /* release */
- g_ptr_array_free(terminal->terms, TRUE);
-
- /* quit */
- gtk_widget_destroy(terminal->mainw);
- } else {
- /* remove page */
- g_ptr_array_remove_index(terminal->terms, term->index);
-
- /* decreasing index number after the page be removed */
- for (i=term->index;i<terminal->terms->len;i++) {
- Term *t = g_ptr_array_index(terminal->terms, i);
- t->index--;
- }
-
- /* release */
- gtk_notebook_remove_page(GTK_NOTEBOOK(terminal->notebook), term->index);
- terminal_free(term);
-
- /* if only one page, hide tab */
- if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(terminal->notebook)) == 1) {
- gint xpad;
- gint ypad;
- gint cols;
- gint rows;
-
- /* get original info of VTE */
- Term *t = g_ptr_array_index(terminal->terms, 0);
- vte_terminal_get_padding(VTE_TERMINAL(t->vte), &xpad, &ypad);
- cols = vte_terminal_get_column_count(VTE_TERMINAL(t->vte));
- rows = vte_terminal_get_row_count(VTE_TERMINAL(t->vte));
-
- /* fixed VTE size */
- terminal_window_set_fixed_size(terminal);
-
- /* hide tab */
- gtk_notebook_set_show_tabs(GTK_NOTEBOOK(terminal->notebook), FALSE);
-
- /* recovery window size */
- vte_terminal_set_size(VTE_TERMINAL(t->vte), cols, rows);
- gtk_window_resize(GTK_WINDOW(terminal->mainw),
- xpad + VTE_TERMINAL(t->vte)->char_width,
- ypad + VTE_TERMINAL(t->vte)->char_height);
- }
- }
+ if (event->button == 2)
+ {
+ /* Middle click closes the tab. */
+ terminal_child_exited_event(NULL, term);
+ return TRUE;
+ }
+ return FALSE;
}
-static gboolean terminal_vte_button_press(VteTerminal *vte, GdkEventButton *event, gpointer data)
+/* Handler for "button-press-event" signal on VTE. */
+static gboolean terminal_vte_button_press_event(VteTerminal * vte, GdkEventButton * event, Term * term)
{
- LXTerminal *terminal = (LXTerminal *)data;
- GtkWidget *menu_item;
- GtkActionGroup *action_group;
- GtkUIManager *manager;
- guint merge_id;
- gint i;
-
- /* right-click */
- if (event->button == 3) {
- /* initializing UI manager */
- manager = gtk_ui_manager_new();
- action_group = gtk_action_group_new("VTEMenu");
- gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
- gtk_action_group_add_actions(action_group, vte_menu_items, VTE_MENUITEM_COUNT, terminal);
- gtk_ui_manager_insert_action_group(manager, action_group, 0);
-
- merge_id = gtk_ui_manager_new_merge_id(manager);
-
- gtk_ui_manager_add_ui(manager, merge_id, "/", "VTEMenu", NULL, GTK_UI_MANAGER_POPUP, FALSE);
- for (i=1;i<VTE_MENUITEM_COUNT;i++) {
- if (strcmp(vte_menu_items[i].label, "Sep")==0)
- gtk_ui_manager_add_ui(manager, merge_id, "/VTEMenu", vte_menu_items[i].name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
- else
- gtk_ui_manager_add_ui(manager, merge_id, "/VTEMenu", vte_menu_items[i].name, vte_menu_items[i].name, GTK_UI_MANAGER_MENUITEM, FALSE);
- }
-
- gtk_menu_popup(GTK_MENU(gtk_ui_manager_get_widget(manager, "/VTEMenu")), NULL, NULL, NULL, NULL, event->button, event->time);
- } else if (event->button == 1) { /* left click */
- /* steal from tilda-0.09.6/src/tilda_terminal.c:743 */
- gint tag;
- gint xpad, ypad;
- gchar* match;
- gchar* cmd;
- gboolean ret = FALSE;
-
- vte_terminal_get_padding(vte, &xpad, &ypad);
- match = vte_terminal_match_check(vte,
- (event->x - xpad) / vte->char_width,
- (event->y - ypad) / vte->char_height,
- &tag);
-
- /* Check if we can launch a web browser, and do so if possible */
- if ((event->state & GDK_CONTROL_MASK) && match != NULL) {
-#if DEBUG
- g_print("Got a Ctrl+Left Click -- Matched: `%s' (%d)\n", match, tag);
-#endif
- cmd = g_strdup_printf("%s %s", "xdg-open", match);
-#if DEBUG
- g_print("Launching command: `%s'\n", cmd);
-#endif
- ret = g_spawn_command_line_async(cmd, NULL);
-
- /* Check that the command launched */
- if (!ret) {
- g_printerr(_("Failed to launch the web browser. The command was `%s'\n"), cmd);
- }
-
- g_free(cmd);
- }
-
- /* Always free match if it is non NULL */
- if (match)
- g_free(match);
- }
-
-#if 0
- GtkItemFactory *item_factory;
-
- /* right-click */
- if (event->button == 3) {
- item_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
- gtk_item_factory_set_translate_func(item_factory, gettext, NULL, NULL);
- gtk_item_factory_create_items(item_factory, sizeof(vte_menu_items) / sizeof(vte_menu_items[0]), vte_menu_items, data);
- gtk_menu_popup(GTK_MENU(gtk_item_factory_get_widget(item_factory, "<main>")), NULL, NULL, NULL, NULL, event->button, event->time);
- }
-#endif
- return FALSE;
+ /* Right-click. */
+ if (event->button == 3)
+ {
+ /* Generate popup menu. */
+ GtkUIManager * manager = gtk_ui_manager_new();
+ GtkActionGroup * action_group = gtk_action_group_new("VTEMenu");
+ gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
+ gtk_action_group_add_actions(action_group, vte_menu_items, VTE_MENUITEM_COUNT, term->parent);
+ gtk_ui_manager_insert_action_group(manager, action_group, 0);
+
+ guint merge_id = gtk_ui_manager_new_merge_id(manager);
+ gtk_ui_manager_add_ui(manager, merge_id, "/", "VTEMenu", NULL, GTK_UI_MANAGER_POPUP, FALSE);
+
+ int i;
+ for (i = 1; i < VTE_MENUITEM_COUNT; i += 1)
+ {
+ if (strcmp(vte_menu_items[i].label, "Sep") == 0)
+ gtk_ui_manager_add_ui(manager, merge_id, "/VTEMenu", vte_menu_items[i].name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
+ else gtk_ui_manager_add_ui(manager, merge_id, "/VTEMenu", vte_menu_items[i].name, vte_menu_items[i].name, GTK_UI_MANAGER_MENUITEM, FALSE);
+ }
+ gtk_menu_popup(GTK_MENU(gtk_ui_manager_get_widget(manager, "/VTEMenu")), NULL, NULL, NULL, NULL, event->button, event->time);
+ }
+
+ /* Control left click. */
+ else if ((event->button == 1) && (event->state & GDK_CONTROL_MASK))
+ {
+ /* steal from tilda-0.09.6/src/tilda_terminal.c:743
+ * See if the terminal has matched the regular expression. */
+ GtkBorder * border = terminal_get_border(term);
+ gint tag;
+ gchar * match = vte_terminal_match_check(vte,
+ (event->x - border->left) / vte->char_width,
+ (event->y - border->top) / vte->char_height,
+ &tag);
+ gtk_border_free(border);
+
+ /* Launch xdg-open with the match string. */
+ if (match != NULL)
+ {
+ gchar * cmd = g_strdup_printf("xdg-open %s", match);
+ if ( ! g_spawn_command_line_async(cmd, NULL))
+ g_warning("Failed to launch xdg-open. The command was `%s'\n", cmd);
+ g_free(cmd);
+ g_free(match);
+ }
+ }
+ return FALSE;
}
-void terminal_term_setting_update(Term *term, LXTerminal *terminal){
- vte_terminal_reset((VteTerminal *)term->vte, FALSE, FALSE);
-
- vte_terminal_set_font_from_string((VteTerminal *)term->vte, terminal->setting->fontname);
- vte_terminal_set_word_chars((VteTerminal *)term->vte, terminal->setting->selchars);
- vte_terminal_set_scrollback_lines((VteTerminal *)term->vte, terminal->setting->scrollback);
-
- vte_terminal_set_cursor_blink_mode((VteTerminal *)term->vte, terminal->setting->cursorblinks?VTE_CURSOR_BLINK_ON:VTE_CURSOR_BLINK_OFF);
-
- /* background transparency */
- if( terminal->rgba ){
- /* dirty hack - vte_terminal_queue_background_update
- * doesn't run without changing background */
- vte_terminal_set_color_background((VteTerminal *)term->vte, &terminal->foreground);
- vte_terminal_set_background_transparent((VteTerminal *)term->vte, FALSE);
- vte_terminal_set_opacity((VteTerminal *)term->vte, terminal->setting->bgalpha);
- } else {
- vte_terminal_set_background_transparent((VteTerminal *)term->vte, terminal->setting->bgalpha == 65535 ? FALSE : TRUE);
- vte_terminal_set_background_saturation((VteTerminal *)term->vte, 1-((double)terminal->setting->bgalpha/65535));
- }
-
- vte_terminal_set_colors((VteTerminal *)term->vte, &terminal->foreground, &terminal->background, &linux_color[0], 16);
-
- /* update scrollbar */
- if( terminal->setting->hidescrollbar )
- gtk_widget_hide( term->scrollbar );
- else
- gtk_widget_show( term->scrollbar );
+/* Apply new settings in an LXTerminal to its tab Term. */
+static void terminal_settings_apply_to_term(LXTerminal * terminal, Term * term)
+{
+ Setting * setting = terminal->setting;
+
+ /* Terminal properties. */
+ vte_terminal_reset(VTE_TERMINAL(term->vte), FALSE, FALSE);
+ vte_terminal_set_font_from_string(VTE_TERMINAL(term->vte), setting->font_name);
+ vte_terminal_set_word_chars(VTE_TERMINAL(term->vte), setting->word_selection_characters);
+ vte_terminal_set_scrollback_lines(VTE_TERMINAL(term->vte), setting->scrollback);
+ vte_terminal_set_allow_bold(VTE_TERMINAL(term->vte), ! setting->disallow_bold);
+ vte_terminal_set_cursor_blink_mode(VTE_TERMINAL(term->vte), ((setting->cursor_blink) ? VTE_CURSOR_BLINK_ON : VTE_CURSOR_BLINK_OFF));
+ vte_terminal_set_cursor_shape(VTE_TERMINAL(term->vte), ((setting->cursor_underline) ? VTE_CURSOR_SHAPE_UNDERLINE : VTE_CURSOR_SHAPE_BLOCK));
+ vte_terminal_set_audible_bell(VTE_TERMINAL(term->vte), setting->audible_bell);
+
+ /* Background and foreground colors. */
+ if (terminal->rgba)
+ {
+ /* vte_terminal_queue_background_update doesn't run without changing background. */
+ vte_terminal_set_color_background(VTE_TERMINAL(term->vte), &setting->foreground_color);
+ vte_terminal_set_background_transparent(VTE_TERMINAL(term->vte), FALSE);
+ vte_terminal_set_opacity(VTE_TERMINAL(term->vte), setting->background_alpha);
+ }
+ else
+ {
+ vte_terminal_set_background_transparent(VTE_TERMINAL(term->vte), setting->background_alpha == 65535 ? FALSE : TRUE);
+ vte_terminal_set_background_saturation(VTE_TERMINAL(term->vte), 1 - ((double) setting->background_alpha / 65535));
+ }
+ vte_terminal_set_colors(VTE_TERMINAL(term->vte), &setting->foreground_color, &setting->background_color, &linux_color[0], 16);
+
+ /* Hide or show scrollbar. */
+ if (setting->hide_scroll_bar)
+ gtk_widget_hide(term->scrollbar);
+ else gtk_widget_show(term->scrollbar);
+
+ /* Hide or show Close button. */
+ if (setting->hide_close_button)
+ gtk_widget_hide(term->close_button);
+ else gtk_widget_show(term->close_button);
+
+ /* If terminal geometry changed, react to it. */
+ if (setting->geometry_change)
+ terminal_geometry_restore(term);
}
-static Term *terminal_new(LXTerminal *terminal, const gchar *label, const gchar *pwd, gchar **env, const gchar *exec)
+/* Create a new terminal. */
+static Term * terminal_new(LXTerminal * terminal, const gchar * label, const gchar * pwd, gchar * * env, const gchar * exec)
{
- gint ret;
- GRegex *dingus1, *dingus2;
- Term *term;
-
- /* create terminal */
- term = g_new0(Term, 1);
- term->parent = terminal;
- term->vte = vte_terminal_new();
- term->box = gtk_hbox_new(FALSE, 0);
- term->scrollbar = gtk_vscrollbar_new(NULL);
- gtk_box_pack_start(GTK_BOX(term->box), term->vte, TRUE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX(term->box), term->scrollbar, FALSE, TRUE, 0);
-
- /* setting terminal */
- vte_terminal_set_emulation((VteTerminal *)term->vte, "xterm");
-
- /* Set encoding from locale. */
- setlocale(LC_ALL, "");
- vte_terminal_set_encoding((VteTerminal *)term->vte, nl_langinfo(CODESET));
-
- /* fixing bugs for specific environment */
- vte_terminal_set_backspace_binding((VteTerminal *)term->vte, VTE_ERASE_ASCII_DELETE);
- vte_terminal_set_delete_binding((VteTerminal *)term->vte, VTE_ERASE_DELETE_SEQUENCE);
-
- /* disable beeping */
- vte_terminal_set_audible_bell((VteTerminal *)term->vte, FALSE);
-
- if (!gdk_color_parse(terminal->setting->bgcolor, &terminal->background)) {
- terminal->background = (GdkColor){ 0, 0, 0, 0 };
- printf("Bad bgcolor string in config: %s\n", terminal->setting->bgcolor);
- }
-
- if (!gdk_color_parse(terminal->setting->fgcolor, &terminal->foreground)) {
- terminal->foreground = (GdkColor){ 0, 0xaaaa, 0xaaaa, 0xaaaa};
- printf("Bad fgcolor string in config: %s\n", terminal->setting->fgcolor);
- }
-
- /* steal from tilda-0.09.6/src/tilda_terminal.c:145 */
- /* Match URL's, etc */
- dingus1 = g_regex_new(DINGUS1, G_REGEX_OPTIMIZE, 0, NULL);
- dingus2 = g_regex_new(DINGUS2, G_REGEX_OPTIMIZE, 0, NULL);
- ret = vte_terminal_match_add_gregex((VteTerminal *)term->vte, dingus1, 0);
- vte_terminal_match_set_cursor_type((VteTerminal *)term->vte, ret, GDK_HAND2);
- ret = vte_terminal_match_add_gregex((VteTerminal *)term->vte, dingus2, 0);
- vte_terminal_match_set_cursor_type((VteTerminal *)term->vte, ret, GDK_HAND2);
- g_regex_unref(dingus1);
- g_regex_unref(dingus2);
-
- /* create label for tab */
- if (label)
- term->label = lxterminal_tab_label_new(label);
- else
- term->label = lxterminal_tab_label_new(pwd);
-
- lxterminal_tab_label_close_button_clicked(G_CALLBACK(terminal_childexit), term);
-
- /* setting scrollbar */
- gtk_range_set_adjustment(GTK_RANGE(term->scrollbar), VTE_TERMINAL(term->vte)->adjustment);
-
- /* terminal fork */
- if (exec) {
- gchar **command;
- g_shell_parse_argv(exec, NULL, &command, NULL);
- term->pid = vte_terminal_fork_command(VTE_TERMINAL(term->vte), (const char *)*(command), command, env, "/tmp", FALSE, TRUE, TRUE);
- g_strfreev(command);
- } else {
- term->pid = vte_terminal_fork_command(VTE_TERMINAL(term->vte), NULL, NULL, env, pwd, FALSE, TRUE, TRUE);
- }
-
- /* signal handler */
- g_signal_connect(term->vte, "child-exited", G_CALLBACK(terminal_childexit), term);
- g_signal_connect(term->vte, "window-title-changed", G_CALLBACK(terminal_title_changed), term);
- g_signal_connect(term->vte, "button-press-event", G_CALLBACK(terminal_vte_button_press), terminal);
-
- gtk_widget_show_all(term->box);
-
- /* apply other settings */
- terminal_term_setting_update(term, terminal);
-
- return term;
+ /* Create and initialize Term structure for new terminal. */
+ Term * term = g_new0(Term, 1);
+ term->parent = terminal;
+
+ /* Create a VTE and a vertical scrollbar, and place them inside a horizontal box. */
+ term->vte = vte_terminal_new();
+ term->box = gtk_hbox_new(FALSE, 0);
+ term->scrollbar = gtk_vscrollbar_new(NULL);
+ gtk_box_pack_start(GTK_BOX(term->box), term->vte, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(term->box), term->scrollbar, FALSE, TRUE, 0);
+
+ /* Set up the VTE. */
+ setlocale(LC_ALL, "");
+ vte_terminal_set_emulation(VTE_TERMINAL(term->vte), "xterm");
+ vte_terminal_set_encoding(VTE_TERMINAL(term->vte), nl_langinfo(CODESET));
+ vte_terminal_set_backspace_binding(VTE_TERMINAL(term->vte), VTE_ERASE_ASCII_DELETE);
+ vte_terminal_set_delete_binding(VTE_TERMINAL(term->vte), VTE_ERASE_DELETE_SEQUENCE);
+
+ /* steal from tilda-0.09.6/src/tilda_terminal.c:145 */
+ /* Match URL's, etc. */
+ GRegex * dingus1 = g_regex_new(DINGUS1, G_REGEX_OPTIMIZE, 0, NULL);
+ GRegex * dingus2 = g_regex_new(DINGUS2, G_REGEX_OPTIMIZE, 0, NULL);
+ gint ret = vte_terminal_match_add_gregex(VTE_TERMINAL(term->vte), dingus1, 0);
+ vte_terminal_match_set_cursor_type(VTE_TERMINAL(term->vte), ret, GDK_HAND2);
+ ret = vte_terminal_match_add_gregex(VTE_TERMINAL(term->vte), dingus2, 0);
+ vte_terminal_match_set_cursor_type(VTE_TERMINAL(term->vte), ret, GDK_HAND2);
+ g_regex_unref(dingus1);
+ g_regex_unref(dingus2);
+
+ /* Create a horizontal box inside an event box as the toplevel for the tab label. */
+ term->tab = gtk_event_box_new();
+ gtk_widget_set_events(term->tab, GDK_BUTTON_PRESS_MASK);
+ GtkWidget * hbox = gtk_hbox_new(FALSE, 4);
+ gtk_container_add(GTK_CONTAINER(term->tab), hbox);
+
+ /* Create the Close button. */
+ term->close_button = gtk_button_new();
+ gtk_button_set_relief(GTK_BUTTON(term->close_button), GTK_RELIEF_NONE);
+ gtk_button_set_focus_on_click(GTK_BUTTON(term->close_button), FALSE);
+ gtk_container_add(GTK_CONTAINER(term->close_button), gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU));
+
+ /* Make the button as small as possible. */
+ GtkRcStyle * rcstyle = gtk_rc_style_new();
+ rcstyle->xthickness = rcstyle->ythickness = 0;
+ gtk_widget_modify_style(term->close_button, rcstyle);
+ gtk_rc_style_unref(rcstyle),
+
+ /* Create the label. */
+ term->label = gtk_label_new((label != NULL) ? label : pwd);
+ gtk_widget_set_size_request(GTK_WIDGET(term->label), 100, -1);
+ gtk_label_set_ellipsize(GTK_LABEL(term->label), PANGO_ELLIPSIZE_END);
+ gtk_misc_set_alignment(GTK_MISC(term->label), 0.0, 0.5);
+ gtk_misc_set_padding(GTK_MISC(term->label), 0, 0);
+
+ /* Pack everything and show the widget. */
+ gtk_box_pack_start(GTK_BOX(hbox), term->label, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), term->close_button, FALSE, FALSE, 0);
+ gtk_widget_show_all(term->tab);
+
+ /* Set up scrollbar. */
+ gtk_range_set_adjustment(GTK_RANGE(term->scrollbar), VTE_TERMINAL(term->vte)->adjustment);
+
+ /* Fork the process that will have the VTE as its controlling terminal. */
+ if (exec != NULL)
+ {
+ gchar * * command;
+ g_shell_parse_argv(exec, NULL, &command, NULL);
+ term->pid = vte_terminal_fork_command(VTE_TERMINAL(term->vte), (const char *) command[0], command, env, pwd, FALSE, TRUE, TRUE);
+ g_strfreev(command);
+ }
+ else
+ term->pid = vte_terminal_fork_command(VTE_TERMINAL(term->vte), NULL, NULL, env, pwd, FALSE, TRUE, TRUE);
+
+ /* Connect signals. */
+ g_signal_connect(G_OBJECT(term->tab), "button-press-event", G_CALLBACK(terminal_tab_button_press_event), term);
+ g_signal_connect(G_OBJECT(term->close_button), "clicked", G_CALLBACK(terminal_child_exited_event), term);
+ g_signal_connect(G_OBJECT(term->vte), "button-press-event", G_CALLBACK(terminal_vte_button_press_event), term);
+ g_signal_connect(G_OBJECT(term->vte), "child-exited", G_CALLBACK(terminal_child_exited_event), term);
+ g_signal_connect(G_OBJECT(term->vte), "window-title-changed", G_CALLBACK(terminal_window_title_changed_event), term);
+
+ /* Show the widget and return. */
+ gtk_widget_show_all(term->box);
+
+ /* Apply user preferences. */
+ terminal_settings_apply_to_term(terminal, term);
+ return term;
}
-void terminal_free(Term* term)
+/* Deallocate a Term structure. */
+static void terminal_free(Term * term)
{
- GtkAccelGroup *accel_group = term->parent->menubar->accel_group;
- gtk_accel_group_disconnect(accel_group, term->closure);
+ gtk_accel_group_disconnect(term->parent->accel_group, term->closure);
g_free(term);
}
-static Menu *menubar_init(LXTerminal *terminal)
+/* Initialize the menu bar. */
+static void terminal_menubar_initialize(LXTerminal * terminal)
{
- Menu *menubar;
- GtkWidget *menu_item;
- GtkActionGroup *action_group;
- GtkAction *encoding_action;
- GtkUIManager *manager;
- guint merge_id;
- gint i;
- gchar *path, *path_ptr;
-
- /* initializing menu */
- menubar = g_new0(Menu, 1);
-
- /* initializing encoding Action */
-// encoding_action = encoding_action_new("CharacterEncoding");
-
- /* initializing UI manager */
- manager = gtk_ui_manager_new();
- action_group = gtk_action_group_new("MenuBar");
- gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
- gtk_action_group_add_actions(action_group, menus, MENUBAR_MENU_COUNT, terminal);
- gtk_action_group_add_actions(action_group, menu_items, MENUBAR_MENUITEM_COUNT, terminal);
-// gtk_action_group_add_action(action_group, encoding_action);
- gtk_ui_manager_insert_action_group(manager, action_group, 0);
-
- merge_id = gtk_ui_manager_new_merge_id(manager);
-
- gtk_ui_manager_add_ui(manager, merge_id, "/", "MenuBar", NULL, GTK_UI_MANAGER_MENUBAR, FALSE);
-
- /* menus */
- for (i=0;i<MENUBAR_MENU_COUNT;i++) {
- path = g_strdup_printf("/MenuBar/%s", menus[i].name);
- for (path_ptr=path;*path_ptr!='\0';path_ptr++) {
- if (*path_ptr=='_')
- *path_ptr = '/';
- }
-
- path_ptr = g_path_get_dirname(path);
- gtk_ui_manager_add_ui(manager, merge_id, path_ptr, menus[i].name, menus[i].name, GTK_UI_MANAGER_MENU, FALSE);
- g_free(path);
- g_free(path_ptr);
- }
-
- /* items */
- for (i=0;i<MENUBAR_MENUITEM_COUNT;i++) {
- path = g_strdup_printf("/MenuBar/%s", menu_items[i].name);
- for (path_ptr=path;*path_ptr!='\0';path_ptr++) {
- if (*path_ptr=='_')
- *path_ptr = '/';
- }
-
- path_ptr = g_path_get_dirname(path);
-
- if (strcmp(menu_items[i].label, "Sep")==0) {
- gtk_ui_manager_add_ui(manager, merge_id, path_ptr, menu_items[i].name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
-#if 0
- /* Encoding */
- } else if (strcmp(menu_items[i].name, "View_CharacterEncoding")==0) {
- gtk_ui_manager_add_ui(manager, merge_id, path_ptr, menu_items[i].name, "CharacterEncoding", GTK_UI_MANAGER_MENUITEM, FALSE);
-#endif
- } else {
- gtk_ui_manager_add_ui(manager, merge_id, path_ptr, menu_items[i].name, menu_items[i].name, GTK_UI_MANAGER_MENUITEM, FALSE);
- }
-
- g_free(path);
- g_free(path_ptr);
- }
-
- menubar->menu = gtk_ui_manager_get_widget(manager, "/MenuBar");
-
- return menubar;
+ /* Initialize UI manager. */
+ GtkUIManager * manager = gtk_ui_manager_new();
+ GtkActionGroup * action_group = gtk_action_group_new("MenuBar");
+ gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
+ gtk_action_group_add_actions(action_group, menus, MENUBAR_MENU_COUNT, terminal);
+ gtk_action_group_add_actions(action_group, menu_items, MENUBAR_MENUITEM_COUNT, terminal);
+ gtk_ui_manager_insert_action_group(manager, action_group, 0);
+
+ guint merge_id = gtk_ui_manager_new_merge_id(manager);
+ gtk_ui_manager_add_ui(manager, merge_id, "/", "MenuBar", NULL, GTK_UI_MANAGER_MENUBAR, FALSE);
+
+ /* Menus. */
+ int i;
+ for (i = 0; i < MENUBAR_MENU_COUNT; i += 1)
+ {
+ gchar * path = g_strdup_printf("/MenuBar/%s", menus[i].name);
+ gchar * path_ptr;
+ for (path_ptr = path; *path_ptr != '\0'; path_ptr += 1)
+ {
+ if (*path_ptr == '_')
+ *path_ptr = '/';
+ }
+ path_ptr = g_path_get_dirname(path);
+ gtk_ui_manager_add_ui(manager, merge_id, path_ptr, menus[i].name, menus[i].name, GTK_UI_MANAGER_MENU, FALSE);
+ g_free(path);
+ g_free(path_ptr);
+ }
+
+ /* Items. */
+ for (i = 0; i < MENUBAR_MENUITEM_COUNT; i += 1)
+ {
+ gchar * path = g_strdup_printf("/MenuBar/%s", menu_items[i].name);
+ gchar * path_ptr;
+ for (path_ptr = path; *path_ptr != '\0'; path_ptr += 1)
+ {
+ if (*path_ptr == '_')
+ *path_ptr = '/';
+ }
+ path_ptr = g_path_get_dirname(path);
+ if (strcmp(menu_items[i].label, "Sep") == 0)
+ gtk_ui_manager_add_ui(manager, merge_id, path_ptr, menu_items[i].name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE);
+ else gtk_ui_manager_add_ui(manager, merge_id, path_ptr, menu_items[i].name, menu_items[i].name, GTK_UI_MANAGER_MENUITEM, FALSE);
+
+ g_free(path);
+ g_free(path_ptr);
+ }
+
+ terminal->menu = gtk_ui_manager_get_widget(manager, "/MenuBar");
}
-static void lxterminal_accelerator_init(LXTerminal *terminal)
+/* Allocate, initialize, and connect up an accelerator group for the accelerators on a new terminal. */
+static void terminal_accelerator_initialize(LXTerminal * terminal)
{
- guint key;
- GdkModifierType mods;
+ guint key;
+ GdkModifierType mods;
+
+ terminal->accel_group = gtk_accel_group_new();
- terminal->menubar->accel_group = gtk_accel_group_new();
+ gtk_accelerator_parse(NEW_WINDOW_ACCEL, &key, &mods);
+ gtk_accel_group_connect(terminal->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_new_window_accelerator), terminal, NULL));
- gtk_accelerator_parse(NEW_WINDOW_ACCEL, &key, &mods);
- gtk_accel_group_connect(terminal->menubar->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_newwindow_accel), terminal, NULL));
+ gtk_accelerator_parse(QUIT_ACCEL, &key, &mods);
+ gtk_accel_group_connect(terminal->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(gtk_main_quit), NULL, NULL));
- gtk_accelerator_parse(QUIT_ACCEL, &key, &mods);
- gtk_accel_group_connect(terminal->menubar->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(gtk_main_quit), NULL, NULL));
+ gtk_accelerator_parse(NEW_TAB_ACCEL, &key, &mods);
+ gtk_accel_group_connect(terminal->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_new_tab_accelerator), terminal, NULL));
- gtk_accelerator_parse(NEW_TAB_ACCEL, &key, &mods);
- gtk_accel_group_connect(terminal->menubar->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_newtab_accel), terminal, NULL));
+ gtk_accelerator_parse(CLOSE_TAB_ACCEL, &key, &mods);
+ gtk_accel_group_connect(terminal->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_close_tab_accelerator), terminal, NULL));
- gtk_accelerator_parse(CLOSE_TAB_ACCEL, &key, &mods);
- gtk_accel_group_connect(terminal->menubar->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_closetab_accel), terminal, NULL));
+ gtk_accelerator_parse(COPY_ACCEL, &key, &mods);
+ gtk_accel_group_connect(terminal->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_copy_accelerator), terminal, NULL));
- gtk_accelerator_parse(COPY_ACCEL, &key, &mods);
- gtk_accel_group_connect(terminal->menubar->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_copy_accel), terminal, NULL));
+ gtk_accelerator_parse(PASTE_ACCEL, &key, &mods);
+ gtk_accel_group_connect(terminal->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_paste_accelerator), terminal, NULL));
- gtk_accelerator_parse(PASTE_ACCEL, &key, &mods);
- gtk_accel_group_connect(terminal->menubar->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_paste_accel), terminal, NULL));
+ gtk_accelerator_parse(NAME_TAB_ACCEL, &key, &mods);
+ gtk_accel_group_connect(terminal->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_name_tab_accelerator), terminal, NULL));
- gtk_accelerator_parse(NEXT_TAB_ACCEL, &key, &mods);
- gtk_accel_group_connect(terminal->menubar->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_nexttab_accel), terminal, NULL));
+ gtk_accelerator_parse(PREVIOUS_TAB_ACCEL, &key, &mods);
+ gtk_accel_group_connect(terminal->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_previous_tab_accelerator), terminal, NULL));
- gtk_accelerator_parse(PREVIOUS_TAB_ACCEL, &key, &mods);
- gtk_accel_group_connect(terminal->menubar->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_prevtab_accel), terminal, NULL));
+ gtk_accelerator_parse(NEXT_TAB_ACCEL, &key, &mods);
+ gtk_accel_group_connect(terminal->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_next_tab_accelerator), terminal, NULL));
- gtk_accelerator_parse(MOVE_TAB_LEFT_ACCEL, &key, &mods);
- gtk_accel_group_connect(terminal->menubar->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_movetableft_accel), terminal, NULL));
+ gtk_accelerator_parse(MOVE_TAB_LEFT_ACCEL, &key, &mods);
+ gtk_accel_group_connect(terminal->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_move_tab_left_accelerator), terminal, NULL));
- gtk_accelerator_parse(MOVE_TAB_RIGHT_ACCEL, &key, &mods);
- gtk_accel_group_connect(terminal->menubar->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_movetabright_accel), terminal, NULL));
+ gtk_accelerator_parse(MOVE_TAB_RIGHT_ACCEL, &key, &mods);
+ gtk_accel_group_connect(terminal->accel_group, key, mods, GTK_ACCEL_LOCKED, g_cclosure_new_swap(G_CALLBACK(terminal_move_tab_right_accelerator), terminal, NULL));
- gtk_window_add_accel_group(GTK_WINDOW(terminal->mainw), terminal->menubar->accel_group);
+ gtk_window_add_accel_group(GTK_WINDOW(terminal->window), terminal->accel_group);
}
-void lxterminal_menuaccel_update(LXTerminal *terminal)
+/* Update the accelerator that brings up the menu.
+ * We have a user preference as to whether F10 (or a style-supplied alternate) is used for this purpose.
+ * Technique taken from gnome-terminal. */
+static void terminal_menu_accelerator_update(LXTerminal * terminal)
{
- /* update F10 status */
- /* hack took from gnome-terminal */
-
- if (saved_menu_accel == NULL) {
- g_object_get (G_OBJECT (gtk_settings_get_default ()),
- "gtk-menu-bar-accel",
- &saved_menu_accel,
- NULL);
- /* FIXME if gtkrc is reparsed we don't catch on,
- * I guess.
- */
- }
-
-
- if (terminal->setting->disablef10) {
- gtk_settings_set_string_property (gtk_settings_get_default(),
- "gtk-menu-bar-accel",
- /* no one will ever press this ;-) */
- "<Shift><Control><Mod1><Mod2><Mod3><Mod4><Mod5>F10",
- "lxterminal");
- } else {
- gtk_settings_set_string_property (gtk_settings_get_default(),
- "gtk-menu-bar-accel",
- saved_menu_accel,
- "lxterminal");
- }
+ /* Ensure that saved_menu_accelerator is initialized. */
+ if (saved_menu_accelerator == NULL)
+ g_object_get(G_OBJECT(gtk_settings_get_default()), "gtk-menu-bar-accel", &saved_menu_accelerator, NULL);
+
+ /* If F10 is disabled, set the accelerator to a key combination that is not F10 and unguessable. */
+ gtk_settings_set_string_property(
+ gtk_settings_get_default(),
+ "gtk-menu-bar-accel",
+ ((terminal->setting->disable_f10) ? "<Shift><Control><Mod1><Mod2><Mod3><Mod4><Mod5>F10" : saved_menu_accelerator),
+ "lxterminal");
}
-void terminal_setting_update(LXTerminal *terminal)
+/* Process the argument vector into the CommandArguments structure.
+ * This is called from the main entry, and also from the controlling socket flow. */
+gboolean lxterminal_process_arguments(gint argc, gchar * * argv, CommandArguments * arguments)
{
- gint i;
+ /* Loop over the argument vector to produce the CommandArguments structure. */
+ memset(arguments, 0, sizeof(CommandArguments));
+ arguments->executable = argv[0];
+
+ gboolean login_shell = FALSE;
+ char * * argv_cursor = argv + 1;
+ argc -= 1;
+ while (argc > 0)
+ {
+ char * argument = *argv_cursor;
+
+ /* --command=<command> */
+ if (strncmp(argument, "--command=", 10) == 0)
+ {
+ g_free(arguments->command);
+ arguments->command = g_strdup(&argument[10]);
+ }
+
+ /* -e <rest of arguments>, --command <rest of arguments>
+ * The <rest of arguments> behavior is demanded by distros who insist on this xterm feature. */
+ else if ((strcmp(argument, "--command") == 0) || (strcmp(argument, "-e") == 0))
+ {
+ while (argc > 1)
+ {
+ argc -= 1;
+ argv_cursor += 1;
+ if (arguments->command == NULL)
+ arguments->command = g_strdup(*argv_cursor);
+ else
+ {
+ gchar * new_command = g_strconcat(arguments->command, " ", *argv_cursor, NULL);
+ g_free(arguments->command);
+ arguments->command = new_command;
+ }
+ }
+ }
+
+ /* --geometry=<columns>x<rows> */
+ else if (strncmp(argument, "--geometry=", 11) == 0)
+ {
+ int result = sscanf(&argument[11], "%dx%d", &arguments->geometry_columns, &arguments->geometry_rows);
+ if (result != 2)
+ return FALSE;
+ }
+
+ /* -l, --loginshell */
+ else if ((strcmp(argument, "--loginshell") == 0) || (strcmp(argument, "-l") == 0))
+ login_shell = TRUE;
+
+ /* --title=<title> */
+ else if (strncmp(argument, "--title=", 8) == 0)
+ arguments->title = &argument[8];
+
+ /* -t <title>, -T <title>, --title <title>
+ * The -T form is demanded by distros who insist on this xterm feature. */
+ else if (((strcmp(argument, "--title") == 0) || (strcmp(argument, "-t") == 0) || (strcmp(argument, "-T") == 0))
+ && (argc > 1))
+ {
+ argc -= 1;
+ argv_cursor += 1;
+ arguments->title = *argv_cursor;
+ }
+
+ /* --working-directory=<working directory> */
+ else if (strncmp(argument, "--working-directory=", 20) == 0)
+ arguments->working_directory = &argument[20];
+
+ /* Undefined argument. */
+ else
+ return FALSE;
+
+ argc -= 1;
+ argv_cursor += 1;
+ }
+
+ /* Handle --loginshell. */
+ if (login_shell)
+ {
+ if (arguments->command == NULL)
+ arguments->command = g_strdup("sh -l");
+ else
+ {
+ gchar * escaped_command = g_shell_quote(arguments->command);
+ gchar * new_command = g_strdup_printf("sh -l -c %s", escaped_command);
+ g_free(escaped_command);
+ g_free(arguments->command);
+ arguments->command = new_command;
+ }
+ }
+ return TRUE;
+}
+
+/* Initialize a new LXTerminal.
+ * This is a toplevel window that may contain tabs, each of which will contain a VTE controlled by a process. */
+LXTerminal * lxterminal_initialize(LXTermWindow * lxtermwin, CommandArguments * arguments, Setting * setting)
+{
+ /* Allocate and initialize the LXTerminal structure. */
+ LXTerminal * terminal = g_new0(LXTerminal, 1);
+ terminal->parent = lxtermwin;
+ terminal->terms = g_ptr_array_new();
+ terminal->fixed_size = TRUE;
+ g_ptr_array_add(lxtermwin->windows, terminal);
+ terminal->index = terminal->parent->windows->len - 1;
+ terminal->setting = setting;
+
+ /* Create toplevel window. */
+ terminal->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ /* Try to get an RGBA colormap and assign it to the new window. */
+ GdkColormap * colormap = gdk_screen_get_rgba_colormap(gtk_widget_get_screen(GTK_WIDGET(terminal->window)));
+ if (colormap != NULL)
+ gtk_widget_set_colormap(terminal->window, colormap);
+
+ /* Set window title. */
+ gtk_window_set_title(GTK_WINDOW(terminal->window), ((arguments->title != NULL) ? arguments->title : _("LXTerminal")));
+
+ /* Set window icon. */
+ gtk_window_set_icon_from_file(GTK_WINDOW(terminal->window), PACKAGE_DATA_DIR "/pixmaps/lxterminal.png", NULL);
+ g_object_weak_ref(G_OBJECT(terminal->window), (GWeakNotify) terminal_window_exit, terminal);
+
+ /* Create a vertical box as the child of the toplevel window. */
+ terminal->box = gtk_vbox_new(FALSE, 1);
+ gtk_container_add(GTK_CONTAINER(terminal->window), terminal->box);
+
+ /* Create the menu bar as the child of the vertical box. */
+ terminal_menubar_initialize(terminal);
+ gtk_box_pack_start(GTK_BOX(terminal->box), terminal->menu, FALSE, TRUE, 0);
+
+ /* Create a notebook as the child of the vertical box. */
+ terminal->notebook = gtk_notebook_new();
+ gtk_notebook_set_scrollable(GTK_NOTEBOOK(terminal->notebook), TRUE);
+ gtk_notebook_set_show_tabs(GTK_NOTEBOOK(terminal->notebook), FALSE);
+ gtk_notebook_set_show_border(GTK_NOTEBOOK(terminal->notebook), FALSE);
+ gtk_box_pack_start(GTK_BOX(terminal->box), terminal->notebook, TRUE, TRUE, 0);
+
+ /* Initialize tab position. */
+ terminal->tab_position = terminal_tab_get_position_id(terminal->setting->tab_position);
+
+ /* Connect signals. */
+ g_signal_connect_swapped(G_OBJECT(terminal->window), "composited-changed", G_CALLBACK(terminal_settings_apply), terminal);
+ g_signal_connect(G_OBJECT(terminal->notebook), "switch-page", G_CALLBACK(terminal_switch_page_event), terminal);
+
+ /* Create the first terminal. */
+ gchar * local_working_directory = NULL;
+ if (arguments->working_directory == NULL)
+ local_working_directory = g_get_current_dir();
+ Term * term = terminal_new(
+ terminal,
+ _("LXTerminal"),
+ ((arguments->working_directory != NULL) ? arguments->working_directory : local_working_directory),
+ NULL,
+ arguments->command);
+ g_free(local_working_directory);
+
+ /* Set the terminal geometry. */
+ if ((arguments->geometry_columns != 0) && (arguments->geometry_rows != 0))
+ vte_terminal_set_size(VTE_TERMINAL(term->vte), arguments->geometry_columns, arguments->geometry_rows);
+
+ /* Add the first terminal to the notebook and the data structures. */
+ gtk_notebook_append_page(GTK_NOTEBOOK(terminal->notebook), term->box, term->tab);
+ term->index = gtk_notebook_get_n_pages(GTK_NOTEBOOK(terminal->notebook)) - 1;
+ g_ptr_array_add(terminal->terms, term);
+
+ /* Initialize accelerators. */
+ terminal_accelerator_initialize(terminal);
+ terminal_initialize_switch_tab_accelerator(term);
+
+ /* Update terminal settings. */
+ terminal_settings_apply(terminal);
+
+ /* Show the widget, so it is realized and has a window. */
+ gtk_widget_show_all(terminal->window);
+
+ /* Initialize the geometry hints. */
+ gdk_window_get_geometry_hints(GTK_WIDGET(term->vte)->window, &terminal->geometry, &terminal->geometry_mask);
+
+ /* Connect signals. */
+ g_signal_connect(G_OBJECT(terminal->window), "size-request", G_CALLBACK(terminal_window_size_request_event), terminal);
+ return terminal;
+}
- /* know if it is composited */
- terminal->rgba = gtk_widget_is_composited( GTK_WIDGET(terminal->mainw) );
+/* Apply new settings to a terminal. */
+static void terminal_settings_apply(LXTerminal * terminal)
+{
+ /* Reinitialize "composited". */
+ terminal->rgba = gtk_widget_is_composited(terminal->window);
- /* update all of terminals */
- for (i=0;i<terminal->terms->len;i++)
- terminal_term_setting_update(g_ptr_array_index(terminal->terms, i), terminal);
+ /* Apply settings to all windows. */
+ int i;
+ for (i = 0; i < terminal->terms->len; i += 1)
+ terminal_settings_apply_to_term(terminal, g_ptr_array_index(terminal->terms, i));
- /* update tab position */
- lxterminal_tab_set_position(terminal->notebook, terminal->tabpos);
+ /* Update tab position. */
+ terminal->tab_position = terminal_tab_get_position_id(terminal->setting->tab_position);
+ terminal_tab_set_position(terminal->notebook, terminal->tab_position);
- /* update menu accel */
- lxterminal_menuaccel_update(terminal);
+ /* Update menu accelerators. */
+ terminal_menu_accelerator_update(terminal);
- /* update menubar */
- if( terminal->setting->hidemenubar )
- gtk_widget_hide( terminal->menubar->menu );
- else
- gtk_widget_show( terminal->menubar->menu );
+ /* Hide or show menubar. */
+ if (terminal->setting->hide_menu_bar)
+ gtk_widget_hide(terminal->menu);
+ else gtk_widget_show(terminal->menu);
}
-LXTerminal *lxterminal_init(LXTermWindow *lxtermwin, gint argc, gchar **argv, Setting *setting)
+/* Apply terminal settings to all tabs in all terminals. */
+void terminal_settings_apply_to_all(LXTerminal * terminal)
{
- LXTerminal *terminal;
- Term *term = NULL;
- gchar *cmd = NULL;
- gchar *workdir = NULL;
- gchar *title = NULL;
- gint cols = 0, rows = 0;
-
- /* argument */
- if (argc>1) {
- int i;
-
- for (i=1;i<argc;i++) {
- if (strncmp(argv[i],"--command=", 10)==0) {
- cmd = argv[i]+10;
- continue;
- } else if ((strcmp(argv[i],"--command")==0 || strcmp(argv[i],"-e") == 0) && (i+1<argc) ) {
- cmd = argv[++i];
- continue;
- } else if (strncmp(argv[i],"--title=", 8)==0) {
- title = argv[i]+8;
- continue;
- } else if ((strcmp(argv[i],"--title")==0 || strcmp(argv[i],"-t")==0 || strcmp(argv[i],"-T")==0)&&(i+1<argc)) {
- title = argv[++i];
- continue;
- } else if (strncmp(argv[i],"--working-directory=", 20)==0) {
- workdir = g_strdup(argv[i]+20);
- continue;
- } else if (strncmp(argv[i],"--geometry=", 11)==0) {
- sscanf(argv[i]+11, "%dx%d", &cols, &rows);
- continue;
- } else if ((strcmp(argv[i],"--loginshell")==0 || strcmp(argv[i],"-l")==0)&&cmd==NULL) {
- cmd = "sh -l";
- }
- }
- }
-
- terminal = g_new0(LXTerminal, 1);
- terminal->parent = lxtermwin;
- terminal->terms = g_ptr_array_new();
- terminal->fixedsize = TRUE;
-
- g_ptr_array_add(lxtermwin->windows, terminal);
- terminal->index = terminal->parent->windows->len - 1;
-
- /* Setting */
- if (setting)
- terminal->setting = setting;
-
- /* create window */
- terminal->mainw = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
- /* colormap assign */
- GdkColormap *colormap = gdk_screen_get_rgba_colormap( gtk_widget_get_screen( GTK_WIDGET(terminal->mainw) ) );
- if (colormap) gtk_widget_set_colormap( GTK_WIDGET(terminal->mainw), colormap );
-
- /* when composited changed, reload the terminal settings */
- g_signal_connect_swapped(GTK_WIDGET(terminal->mainw), "composited-changed", G_CALLBACK(terminal_setting_update), terminal);
-
- if (!title)
- gtk_window_set_title(GTK_WINDOW(terminal->mainw), _("LXTerminal"));
- else
- gtk_window_set_title(GTK_WINDOW(terminal->mainw), title);
-
- gtk_window_set_icon_from_file(GTK_WINDOW(terminal->mainw), PACKAGE_DATA_DIR "/pixmaps/lxterminal.png", NULL);
- g_object_weak_ref((GObject *) terminal->mainw, terminal_windowexit, terminal);
-
- /* create box for putting menubar and notebook */
- terminal->box = gtk_vbox_new(FALSE, 1);
- gtk_container_add(GTK_CONTAINER(terminal->mainw), terminal->box);
-
- /* create menubar */
- terminal->menubar = menubar_init(terminal);
- gtk_box_pack_start(GTK_BOX(terminal->box), terminal->menubar->menu, FALSE, TRUE, 0);
-
- /* create notebook */
- terminal->notebook = gtk_notebook_new();
- gtk_notebook_set_scrollable(GTK_NOTEBOOK(terminal->notebook), TRUE);
- gtk_notebook_set_show_tabs(GTK_NOTEBOOK(terminal->notebook), FALSE);
- gtk_notebook_set_show_border(GTK_NOTEBOOK(terminal->notebook), FALSE);
-
- /* Tab Position */
- terminal->tabpos = lxterminal_tab_get_position_id(terminal->setting->tabpos);
-
- g_signal_connect(terminal->notebook, "switch-page", G_CALLBACK(terminal_switch_tab), terminal);
- gtk_box_pack_start(GTK_BOX(terminal->box), terminal->notebook, TRUE, TRUE, 0);
-
- if ( ! workdir) workdir = g_get_current_dir();
- term = terminal_new(terminal, _("LXTerminal"), workdir, NULL, cmd);
- g_free(workdir);
-
- /* set default cols and rows */
- if (cols&&rows)
- vte_terminal_set_size(VTE_TERMINAL(term->vte), cols, rows);
-
- gtk_notebook_append_page(GTK_NOTEBOOK(terminal->notebook), term->box, term->label->main);
- term->index = gtk_notebook_get_n_pages(GTK_NOTEBOOK(terminal->notebook)) - 1;
- g_ptr_array_add(terminal->terms, term);
-
- /* initializing accelerator */
- lxterminal_accelerator_init(terminal);
- term_set_swicth_accel(term);
-
- gtk_widget_show_all(terminal->mainw);
-
- /* update terminal settings */
- terminal_setting_update(terminal);
-
- /* original hints of VTE */
- gdk_window_get_geometry_hints(GTK_WIDGET(term->vte)->window,
- &terminal->geometry,
- &terminal->geom_mask);
-
- /* resizing terminal with window size */
- g_signal_connect(terminal->mainw, "size-request", G_CALLBACK(terminal_window_resize), terminal);
-
- return terminal;
+ /* Apply settings to all open windows. */
+ g_ptr_array_foreach(terminal->parent->windows, (GFunc) terminal_settings_apply, terminal->setting);
+ terminal->setting->geometry_change = FALSE;
}
-int main(gint argc, gchar** argv)
+/* Main entry point. */
+int main(gint argc, gchar * * argv)
{
- LXTermWindow *lxtermwin;
- Setting *setting;
- gchar *dir, *path;
- gint i;
-
- gtk_init(&argc, &argv);
+ /* Initialize GTK. */
+ gtk_init(&argc, &argv);
#ifdef ENABLE_NLS
- bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
- bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
- textdomain ( GETTEXT_PACKAGE );
+ bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+ textdomain(GETTEXT_PACKAGE);
#endif
- if (argc>1) {
- for (i=1;i<argc;i++) {
- if (strncmp(argv[i],"--command=", 10)==0) {
- continue;
- } else if ((strcmp(argv[i],"--command")==0||strcmp(argv[i],"-e")==0)&&(i+1<argc)) {
- i++;
- continue;
- } else if (strncmp(argv[i],"--title=", 8)==0) {
- continue;
- } else if ((strcmp(argv[i],"--title")==0||strcmp(argv[i],"-t")==0||strcmp(argv[i],"-T")==0)&&(i+1<argc)) {
- i++;
- continue;
- } else if (strncmp(argv[i],"--working-directory=", 20)==0) {
- continue;
- } else if (strncmp(argv[i],"--geometry=", 11)==0) {
- continue;
- } else if ((strcmp(argv[i],"--loginshell")==0 || strcmp(argv[i],"-l")==0)) {
- continue;
- }
-
- printf("%s\n", helpmsg);
- return 0;
- }
- }
-
- /* initializing Window Array */
- lxtermwin = g_new0(LXTermWindow, 1);
-
- /* initializing socket */
- if (!lxterminal_socket_init(lxtermwin, argc, argv))
- return 0;
-
- /* load config file */
- dir = g_build_filename(g_get_user_config_dir(), "lxterminal" , NULL);
- g_mkdir_with_parents(dir, 0700);
- path = g_build_filename(dir, "lxterminal.conf", NULL);
- g_free(dir);
-
- if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
- setting = load_setting_from_file(PACKAGE_DATA_DIR "/lxterminal/lxterminal.conf");
- /* save to user's directory */
- setting_save(setting);
- } else {
- setting = load_setting_from_file(path);
- }
-
- g_free(path);
-
- /* initializing something */
- lxtermwin->windows = g_ptr_array_new();
- lxtermwin->setting = setting;
-
- /* initializing LXTerminal */
- lxterminal_init(lxtermwin, argc, argv, setting);
-
- gtk_main();
+ /* Parse the command arguments. If there is an error, display usage help and exit. */
+ CommandArguments arguments;
+ if ( ! lxterminal_process_arguments(argc, argv, &arguments))
+ {
+ printf("%s\n", usage_display);
+ return 0;
+ }
+
+ /* Initialize impure storage. */
+ LXTermWindow * lxtermwin = g_new0(LXTermWindow, 1);
+
+ /* Initialize socket. If we were able to get another LXTerminal to manage the window, exit. */
+ if ( ! lxterminal_socket_initialize(lxtermwin, &arguments))
+ return 0;
+
+ /* Load user preferences. */
+ gchar * dir = g_build_filename(g_get_user_config_dir(), "lxterminal" , NULL);
+ g_mkdir_with_parents(dir, S_IRUSR | S_IWUSR | S_IXUSR);
+ gchar * path = g_build_filename(dir, "lxterminal.conf", NULL);
+ g_free(dir);
+
+ if ( ! g_file_test(path, G_FILE_TEST_EXISTS))
+ {
+ /* Copy the system-wide settings to the user's configuration. */
+ lxtermwin->setting = load_setting_from_file(PACKAGE_DATA_DIR "/lxterminal/lxterminal.conf");
+ setting_save(lxtermwin->setting);
+ }
+ else
+ lxtermwin->setting = load_setting_from_file(path);
+
+ g_free(path);
+
+ /* Finish initializing the impure area and start the first LXTerminal. */
+ lxtermwin->windows = g_ptr_array_new();
+ lxterminal_initialize(lxtermwin, &arguments, lxtermwin->setting);
+
+ /* Run the main loop. */
+ gtk_main();
return 0;
}
diff --git a/src/lxterminal.h b/src/lxterminal.h
index 175d5a3..2e5e873 100644
--- a/src/lxterminal.h
+++ b/src/lxterminal.h
@@ -1,3 +1,23 @@
+/**
+ * Copyright 2008 Fred Chien <cfsghost@gmail.com>
+ * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
#ifndef LXTERMINAL_H
#define LXTERMINAL_H
@@ -9,7 +29,7 @@
#define QUIT_ACCEL "<CTRL><SHIFT>Q"
#define COPY_ACCEL "<CTRL><SHIFT>C"
#define PASTE_ACCEL "<CTRL><SHIFT>V"
-#define RENAME_TAB_ACCEL "<CTRL><SHIFT>R"
+#define NAME_TAB_ACCEL "<CTRL><SHIFT>I"
#define PREVIOUS_TAB_ACCEL "<CTRL>Page_Up"
#define NEXT_TAB_ACCEL "<CTRL>Page_Down"
#define MOVE_TAB_LEFT_ACCEL "<CTRL><SHIFT>Page_Up"
@@ -19,58 +39,59 @@
#define DINGUS1 "(((news|telnet|nttp|file|http|ftp|https)://)|(www|ftp)[-A-Za-z0-9]*\\.)[-A-Za-z0-9\\.]+(:[0-9]*)?"
#define DINGUS2 "(((news|telnet|nttp|file|http|ftp|https)://)|(www|ftp)[-A-Za-z0-9]*\\.)[-A-Za-z0-9\\.]+(:[0-9]*)?/[-A-Za-z0-9_\\$\\.\\+\\!\\*\\(\\),;:@&=\\?/~\\#\\%]*[^]'\\.}>\\) ,\\\"]"
+/* Top level application context. */
typedef struct _lxtermwindow {
- Setting *setting;
- GPtrArray *windows;
+ Setting * setting; /* Pointer to current user preferences */
+ GPtrArray * windows; /* Array of pointers to LXTerminal structures */
} LXTermWindow;
-typedef struct _menu {
- GtkWidget *menu;
- GtkItemFactory *item_factory;
- GtkAccelGroup *accel_group;
-} Menu;
-
+/* Representative of a toplevel window. */
typedef struct _lxterminal {
- LXTermWindow *parent;
- gint index;
- GtkWidget *mainw;
- GtkWidget *box;
- Menu *menubar;
- GtkWidget *notebook;
- GPtrArray *terms;
- gint resize_idle_id;
- Setting *setting;
- GdkGeometry geometry;
- GdkWindowHints geom_mask;
- gboolean fixedsize;
- gboolean rgba;
- GdkColor background;
- GdkColor foreground;
- gint tabpos;
- gboolean hidemenubar;
- gboolean hidescrollbar;
- gint cursormode;
- gboolean cursorblinks;
+ LXTermWindow * parent; /* Back pointer to top level context */
+ gint index; /* Index of this element in parent->windows */
+ GtkWidget * window; /* Toplevel window */
+ GtkWidget * box; /* Vertical box, child of toplevel window */
+ GtkWidget * menu; /* Menu bar, child of vertical box */
+ GtkAccelGroup * accel_group; /* Accelerator group for accelerators on this window */
+ GtkWidget * notebook; /* Notebook, child of vertical box */
+ GPtrArray * terms; /* Array of pointers to Term structures */
+ Setting * setting; /* A copy of parent->setting */
+ GdkGeometry geometry; /* Geometry hints (see XGetWMNormalHints) */
+ GdkWindowHints geometry_mask; /* Mask of valid data in geometry hints */
+ gboolean fixed_size; /* True if the terminal is fixed size */
+ gboolean rgba; /* True if colormap is RGBA */
+ GdkColor background; /* User preference background color converted to GdkColor */
+ GdkColor foreground; /* User preference foreground color converted to GdkColor */
+ gint tab_position; /* Tab position as an integer value */
} LXTerminal;
-typedef struct _tab {
- GtkWidget *main;
- GtkWidget *label;
- GtkWidget *close_btn;
-} LXTab;
-
+/* Representative of a tab within a toplevel window. */
typedef struct _term {
- gint index;
- LXTerminal *parent;
- LXTab *label;
- GtkWidget *vte;
- GtkWidget *scrollbar;
- GtkWidget *box;
- pid_t pid;
- GClosure* closure;
+ LXTerminal * parent; /* Back pointer to LXTerminal */
+ gint index; /* Index of this element in parent->terms */
+ GtkWidget * tab; /* Toplevel of the tab */
+ GtkWidget * label; /* Label of the tab, child of the toplevel */
+ gboolean user_specified_label; /* User did "Name Tab", so we will never overwrite this with the window title */
+ GtkWidget * close_button; /* Close button for the tab, child of the toplevel */
+ GtkWidget * box; /* Horizontal box, child of notebook */
+ GtkWidget * vte; /* VteTerminal, child of horizontal box */
+ GtkWidget * scrollbar; /* Scroll bar, child of horizontal box */
+ pid_t pid; /* Process ID of the process that has this as its terminal */
+ GClosure * closure; /* Accelerator structure */
} Term;
-LXTerminal *lxterminal_init(LXTermWindow *lxtermwin, gint argc, gchar **argv, Setting *setting);
-void terminal_setting_update(LXTerminal *terminal);
+/* Output of lxterminal_process_arguments. */
+typedef struct _command_arguments {
+ char * executable; /* Value of argv[0]; points into argument vector */
+ gchar * command; /* Value of -e, --command; memory allocated by glib */
+ int geometry_columns; /* Value of --geometry */
+ int geometry_rows;
+ char * title; /* Value of -t, -T, --title; points into argument vector */
+ char * working_directory; /* Value of --working-directory; points into argument vector */
+} CommandArguments;
+
+extern gboolean lxterminal_process_arguments(gint argc, gchar * * argv, CommandArguments * arguments);
+extern LXTerminal * lxterminal_initialize(LXTermWindow * lxtermwin, CommandArguments * arguments, Setting * setting);
+extern void terminal_settings_apply_to_all(LXTerminal * terminal);
#endif
diff --git a/src/preferences.c b/src/preferences.c
index 502cd13..913e686 100644
--- a/src/preferences.c
+++ b/src/preferences.c
@@ -1,5 +1,6 @@
-/*
+/**
* Copyright 2008 Fred Chien <cfsghost@gmail.com>
+ * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
*
* 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
@@ -25,378 +26,241 @@
#include "setting.h"
#include "preferences.h"
-#if (GTK_MINOR_VERSION < 12)
-gchar *gdk_color_to_string(const GdkColor *color)
+static void preferences_dialog_response_event(GtkWidget * dialog, gint response, LXTerminal * terminal);
+static void preferences_dialog_font_set_event(GtkFontButton * widget, LXTerminal * terminal);
+static void preferences_dialog_background_color_set_event(GtkColorButton * widget, LXTerminal * terminal);
+static void preferences_dialog_foreground_color_set_event(GtkColorButton * widget, LXTerminal * terminal);
+static void preferences_dialog_allow_bold_toggled_event(GtkToggleButton * widget, LXTerminal * terminal);
+static void preferences_dialog_cursor_blink_toggled_event(GtkToggleButton * widget, LXTerminal * terminal);
+static void preferences_dialog_cursor_underline_toggled_event(GtkToggleButton * widget, LXTerminal * terminal);
+static void preferences_dialog_audible_bell_toggled_event(GtkToggleButton * widget, LXTerminal * terminal);
+static void preferences_dialog_tab_position_changed_event(GtkComboBox * widget, LXTerminal * terminal);
+static void preferences_dialog_scrollback_value_changed_event(GtkSpinButton * widget, LXTerminal * terminal);
+static void preferences_dialog_hide_scroll_bar_toggled_event(GtkToggleButton * widget, LXTerminal * terminal);
+static void preferences_dialog_hide_menu_bar_toggled_event(GtkToggleButton * widget, LXTerminal * terminal);
+static void preferences_dialog_hide_close_button_toggled_event(GtkToggleButton * widget, LXTerminal * terminal);
+static gboolean preferences_dialog_selection_focus_out_event(GtkWidget * widget, GdkEventFocus * event, LXTerminal * terminal);
+static void preferences_dialog_disable_f10_toggled_event(GtkToggleButton * widget, LXTerminal * terminal);
+
+/* Handler for "response" signal on preferences dialog. */
+static void preferences_dialog_response_event(GtkWidget * dialog, gint response, LXTerminal * terminal)
{
- return g_strdup_printf("#%04x%04x%04x", color->red, color->green, color->blue);
+ if (response == GTK_RESPONSE_OK)
+ setting_save(terminal->setting);
+
+ /* Dismiss dialog. */
+ gtk_widget_destroy(dialog);
}
-#endif
-
-void lxterminal_preferences_style_constructor(Prefer *prefer, TabWidget *tab);
-void lxterminal_preferences_style_destructor(Prefer *prefer, TabWidget *tab);
-void lxterminal_preferences_style_save(Prefer *prefer, TabWidget *tab);
-void lxterminal_preferences_display_constructor(Prefer *prefer, TabWidget *tab);
-void lxterminal_preferences_display_destructor(Prefer *prefer, TabWidget *tab);
-void lxterminal_preferences_display_save(Prefer *prefer, TabWidget *tab);
-void lxterminal_preferences_misc_constructor(Prefer *prefer, TabWidget *tab);
-void lxterminal_preferences_misc_destructor(Prefer *prefer, TabWidget *tab);
-void lxterminal_preferences_misc_save(Prefer *prefer, TabWidget *tab);
-
-static TabGroup tabs[] = {
- {
- N_("Style"),
- "preferences-style.png",
- lxterminal_preferences_style_constructor,
- lxterminal_preferences_style_destructor,
- lxterminal_preferences_style_save
- },
- {
- N_("Display"),
- "preferences-display.png",
- lxterminal_preferences_display_constructor,
- lxterminal_preferences_display_destructor,
- lxterminal_preferences_display_save
- },
- {
- N_("Misc"),
- "preferences-misc.png",
- lxterminal_preferences_misc_constructor,
- lxterminal_preferences_misc_destructor,
- lxterminal_preferences_misc_save
- }
-};
-
-void lxterminal_preferences_style_constructor(Prefer *prefer, TabWidget *tab)
+
+/* Handler for "font-set" signal on Terminal Font font button. */
+static void preferences_dialog_font_set_event(GtkFontButton * widget, LXTerminal * terminal)
{
- PreferStyle *ps;
-
- /* create general data structure */
- ps = g_new0(PreferStyle, 1);
- tab->childs = ps;
-
- ps->box = gtk_table_new(4, 4, FALSE);
- gtk_table_set_row_spacings(GTK_TABLE(ps->box), 3);
- gtk_table_set_col_spacings(GTK_TABLE(ps->box), 5);
-
- /* terminal font */
- ps->font_label = gtk_label_new(_("Terminal Font:"));
- gtk_misc_set_alignment(GTK_MISC(ps->font_label), 1, 0.5);
- ps->font_button = gtk_font_button_new_with_font(prefer->terminal->setting->fontname);
- gtk_table_attach_defaults(GTK_TABLE(ps->box), ps->font_label, 0,2, 0,1);
- gtk_table_attach_defaults(GTK_TABLE(ps->box), ps->font_button, 2,4, 0,1);
-
- /* Background color */
- ps->bgcolor_label = gtk_label_new(_("Background:"));
- gtk_misc_set_alignment(GTK_MISC(ps->bgcolor_label), 1, 0.5);
- ps->bgcolor_entry = gtk_color_button_new_with_color(&prefer->terminal->background);
- gtk_color_button_set_use_alpha(GTK_COLOR_BUTTON(ps->bgcolor_entry), TRUE);
- gtk_color_button_set_alpha(GTK_COLOR_BUTTON(ps->bgcolor_entry), prefer->terminal->setting->bgalpha);
- gtk_table_attach_defaults(GTK_TABLE(ps->box), ps->bgcolor_label, 0,2, 1,2);
- gtk_table_attach_defaults(GTK_TABLE(ps->box), ps->bgcolor_entry, 2,4, 1,2);
-
- /* Foreground color */
- ps->fgcolor_label = gtk_label_new(_("Foreground:"));
- gtk_misc_set_alignment(GTK_MISC(ps->fgcolor_label), 1, 0.5);
- ps->fgcolor_entry = gtk_color_button_new_with_color(&prefer->terminal->foreground);
- gtk_table_attach_defaults(GTK_TABLE(ps->box), ps->fgcolor_label, 0,2, 2,3);
- gtk_table_attach_defaults(GTK_TABLE(ps->box), ps->fgcolor_entry, 2,4, 2,3);
-
- /* Cursor Blinks */
- ps->cursorblinks_label = gtk_label_new(_("Cursor Blinks:"));
- gtk_misc_set_alignment(GTK_MISC(ps->cursorblinks_label), 1, 0.5);
- ps->cursorblinks_checkbox = gtk_check_button_new();
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ps->cursorblinks_checkbox), prefer->terminal->setting->cursorblinks);
- gtk_table_attach_defaults(GTK_TABLE(ps->box), ps->cursorblinks_label, 0,2,3,4);
- gtk_table_attach_defaults(GTK_TABLE(ps->box), ps->cursorblinks_checkbox, 2,4,3,4);
-
- /* adding to page */
- gtk_container_add(GTK_CONTAINER(tab->page), ps->box);
+ g_free(terminal->setting->font_name);
+ terminal->setting->font_name = g_strdup(gtk_font_button_get_font_name(widget));
+ terminal->setting->geometry_change = TRUE; /* Force the terminals to resize */
+ terminal_settings_apply_to_all(terminal);
}
-void lxterminal_preferences_display_constructor(Prefer *prefer, TabWidget *tab)
+/* Handler for "color-set" signal on Background Color color button. */
+static void preferences_dialog_background_color_set_event(GtkColorButton * widget, LXTerminal * terminal)
{
- PreferDisplay *pd;
-
- /* create general data structure */
- pd = g_new0(PreferDisplay, 1);
- tab->childs = pd;
-
- pd->box = gtk_table_new(4,4, FALSE);
- gtk_table_set_row_spacings(GTK_TABLE(pd->box), 3);
- gtk_table_set_col_spacings(GTK_TABLE(pd->box), 5);
-
- /* tab-panel position */
- pd->tabpos_label = gtk_label_new(_("Tab panel position:"));
- gtk_misc_set_alignment(GTK_MISC(pd->tabpos_label), 1, 0.5);
- pd->tabpos_combobox = gtk_combo_box_new_text();
- gtk_combo_box_append_text(GTK_COMBO_BOX (pd->tabpos_combobox), _("Top"));
- gtk_combo_box_append_text(GTK_COMBO_BOX (pd->tabpos_combobox), _("Bottom"));
- gtk_combo_box_append_text(GTK_COMBO_BOX (pd->tabpos_combobox), _("Left"));
- gtk_combo_box_append_text(GTK_COMBO_BOX (pd->tabpos_combobox), _("Right"));
- gtk_combo_box_set_active (GTK_COMBO_BOX (pd->tabpos_combobox), prefer->terminal->tabpos);
- gtk_table_attach_defaults(GTK_TABLE(pd->box), pd->tabpos_label, 0,2, 0,1);
- gtk_table_attach_defaults(GTK_TABLE(pd->box), pd->tabpos_combobox, 2,4, 0,1);
-
- /* Scrollback buffer */
- pd->scrollback_label = gtk_label_new(_("Scrollback lines:"));
- gtk_misc_set_alignment(GTK_MISC(pd->scrollback_label), 1, 0.5);
- pd->scrollback_entry = gtk_spin_button_new_with_range(100, 100000, 10);
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(pd->scrollback_entry), (gdouble)prefer->terminal->setting->scrollback);
- gtk_table_attach_defaults(GTK_TABLE(pd->box), pd->scrollback_label, 0,2, 1,2);
- gtk_table_attach_defaults(GTK_TABLE(pd->box), pd->scrollback_entry, 2,4, 1,2);
-
- /* Hide scroll bar */
- pd->hidescrollbar_label = gtk_label_new(_("Hide scroll bar:"));
- gtk_misc_set_alignment(GTK_MISC(pd->hidescrollbar_label), 1, 0.5);
- pd->hidescrollbar_checkbox = gtk_check_button_new();
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pd->hidescrollbar_checkbox), prefer->terminal->setting->hidescrollbar);
- gtk_table_attach_defaults(GTK_TABLE(pd->box), pd->hidescrollbar_label, 0,2,2,3);
- gtk_table_attach_defaults(GTK_TABLE(pd->box), pd->hidescrollbar_checkbox, 2,4,2,3);
-
- /* Hide menu bar */
- pd->hidemenubar_label = gtk_label_new(_("Hide menu bar:"));
- gtk_misc_set_alignment(GTK_MISC(pd->hidemenubar_label), 1, 0.5);
- pd->hidemenubar_checkbox = gtk_check_button_new();
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pd->hidemenubar_checkbox), prefer->terminal->setting->hidemenubar);
- gtk_table_attach_defaults(GTK_TABLE(pd->box), pd->hidemenubar_label, 0,2,3,4);
- gtk_table_attach_defaults(GTK_TABLE(pd->box), pd->hidemenubar_checkbox, 2,4,3,4);
-
- /* adding to page */
- gtk_container_add(GTK_CONTAINER(tab->page), pd->box);
+ gtk_color_button_get_color(widget, &terminal->setting->background_color);
+ terminal->setting->background_alpha = gtk_color_button_get_alpha(widget);
+ terminal_settings_apply_to_all(terminal);
}
-void lxterminal_preferences_misc_constructor(Prefer *prefer, TabWidget *tab)
+/* Handler for "color-set" signal on Foreground Color color button. */
+static void preferences_dialog_foreground_color_set_event(GtkColorButton * widget, LXTerminal * terminal)
{
- PreferMisc *pm;
-
- /* create general data structure */
- pm = g_new0(PreferMisc, 1);
- tab->childs = pm;
-
- pm->box = gtk_table_new(2,4, FALSE);
- gtk_table_set_row_spacings(GTK_TABLE(pm->box), 3);
- gtk_table_set_col_spacings(GTK_TABLE(pm->box), 5);
-
- /* Select-by-word */
- pm->selchars_label = gtk_label_new(_("Select-by-word characters:"));
- gtk_misc_set_alignment(GTK_MISC(pm->selchars_label), 1, 0.5);
- pm->selchars_entry = gtk_entry_new();
- gtk_entry_set_text(GTK_ENTRY(pm->selchars_entry), prefer->terminal->setting->selchars);
- gtk_table_attach_defaults(GTK_TABLE(pm->box), pm->selchars_label, 0,2, 0,1);
- gtk_table_attach_defaults(GTK_TABLE(pm->box), pm->selchars_entry, 2,4, 0,1);
-
- /* Disable F10 for menu */
- pm->disablef10_label = gtk_label_new(_("Disable F10 shortcut for menu:"));
- gtk_misc_set_alignment(GTK_MISC(pm->disablef10_label), 1, 0.5);
- pm->disablef10_checkbox = gtk_check_button_new();
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pm->disablef10_checkbox), prefer->terminal->setting->disablef10);
- gtk_table_attach_defaults(GTK_TABLE(pm->box), pm->disablef10_label, 0,2, 1,2);
- gtk_table_attach_defaults(GTK_TABLE(pm->box), pm->disablef10_checkbox, 2,4, 1,2);
-
- /* adding to page */
- gtk_container_add(GTK_CONTAINER(tab->page), pm->box);
+ gtk_color_button_get_color(widget, &terminal->setting->foreground_color);
+ terminal_settings_apply_to_all(terminal);
}
-void lxterminal_preferences_style_destructor(Prefer *prefer, TabWidget *tab)
+/* Handler for "toggled" signal on Allow Bold toggle button.
+ * Use the complement so the default is FALSE. */
+static void preferences_dialog_allow_bold_toggled_event(GtkToggleButton * widget, LXTerminal * terminal)
{
- PreferStyle *ps = tab->childs;
-
- g_free(ps);
+ terminal->setting->disallow_bold = ! gtk_toggle_button_get_active(widget);
+ terminal_settings_apply_to_all(terminal);
}
-void lxterminal_preferences_display_destructor(Prefer *prefer, TabWidget *tab)
+/* Handler for "toggled" signal on Cursor Blink toggle button. */
+static void preferences_dialog_cursor_blink_toggled_event(GtkToggleButton * widget, LXTerminal * terminal)
{
- PreferDisplay *pd = tab->childs;
-
- g_free(pd);
+ terminal->setting->cursor_blink = gtk_toggle_button_get_active(widget);
+ terminal_settings_apply_to_all(terminal);
}
-void lxterminal_preferences_misc_destructor(Prefer *prefer, TabWidget *tab)
+/* Handler for "toggled" signal on Cursor Underline radio button. */
+static void preferences_dialog_cursor_underline_toggled_event(GtkToggleButton * widget, LXTerminal * terminal)
{
- PreferMisc *pm = tab->childs;
-
- g_free(pm);
+ terminal->setting->cursor_underline = gtk_toggle_button_get_active(widget);
+ terminal_settings_apply_to_all(terminal);
}
-void lxterminal_preferences_style_save(Prefer *prefer, TabWidget *tab)
+/* Handler for "toggled" signal on Audible Bell radio button. */
+static void preferences_dialog_audible_bell_toggled_event(GtkToggleButton * widget, LXTerminal * terminal)
{
- PreferStyle *ps = tab->childs;
-
- g_free( prefer->terminal->setting->fontname );
- g_free( prefer->terminal->setting->selchars );
- prefer->terminal->setting->fontname = g_strdup( gtk_font_button_get_font_name((GtkFontButton *)ps->font_button) );
- prefer->terminal->setting->bgalpha = (guint16)gtk_color_button_get_alpha(GTK_COLOR_BUTTON(ps->bgcolor_entry));
- prefer->terminal->setting->cursorblinks = (gboolean)gtk_toggle_button_get_active((GtkToggleButton *)ps->cursorblinks_checkbox);
-
- /* background and foreground */
- gtk_color_button_get_color( GTK_COLOR_BUTTON(ps->bgcolor_entry), &prefer->terminal->background);
- prefer->terminal->setting->bgcolor = g_strdup( gdk_color_to_string(&prefer->terminal->background) );
- gtk_color_button_get_color(GTK_COLOR_BUTTON(ps->fgcolor_entry), &prefer->terminal->foreground);
- prefer->terminal->setting->fgcolor = g_strdup( gdk_color_to_string(&prefer->terminal->foreground) );
+ terminal->setting->audible_bell = gtk_toggle_button_get_active(widget);
+ terminal_settings_apply_to_all(terminal);
}
-void lxterminal_preferences_display_save(Prefer *prefer, TabWidget *tab)
+/* Handler for "changed" signal on Tab Position combo box. */
+static void preferences_dialog_tab_position_changed_event(GtkComboBox * widget, LXTerminal * terminal)
{
- PreferDisplay *pd = tab->childs;
-
- prefer->terminal->setting->scrollback = (glong)gtk_spin_button_get_value_as_int((GtkSpinButton *)pd->scrollback_entry);
- prefer->terminal->setting->hidemenubar = (gboolean)gtk_toggle_button_get_active((GtkToggleButton *)pd->hidemenubar_checkbox);
- prefer->terminal->setting->hidescrollbar = (gboolean)gtk_toggle_button_get_active((GtkToggleButton *)pd->hidescrollbar_checkbox);
-
- /* Tab position */
- g_free( prefer->terminal->setting->tabpos );
- prefer->terminal->tabpos = gtk_combo_box_get_active((GtkComboBox *)pd->tabpos_combobox);
- switch(prefer->terminal->tabpos) {
- case 0:
- prefer->terminal->setting->tabpos = g_strdup("top");
- break;
- case 1:
- prefer->terminal->setting->tabpos = g_strdup("bottom");
- break;
- case 2:
- prefer->terminal->setting->tabpos = g_strdup("left");
- break;
- case 3:
- prefer->terminal->setting->tabpos = g_strdup("right");
- break;
- }
+ /* Convert the index into a string, which is what we put in the configuration file. */
+ char * p = NULL;
+ switch (gtk_combo_box_get_active(widget))
+ {
+ case 0: p = "top"; break;
+ case 1: p = "bottom"; break;
+ case 2: p = "left"; break;
+ case 3: p = "right"; break;
+ }
+ if (p != NULL)
+ {
+ g_free(terminal->setting->tab_position);
+ terminal->setting->tab_position = g_strdup(p);
+ }
+ terminal_settings_apply_to_all(terminal);
}
-void lxterminal_preferences_misc_save(Prefer *prefer, TabWidget *tab)
+/* Handler for "value-changed" signal on Scrollback spin button. */
+static void preferences_dialog_scrollback_value_changed_event(GtkSpinButton * widget, LXTerminal * terminal)
{
- PreferMisc *pm = tab->childs;
-
- prefer->terminal->setting->selchars = g_strdup( gtk_entry_get_text((GtkEntry *)pm->selchars_entry) );
- prefer->terminal->setting->disablef10 = (gboolean)gtk_toggle_button_get_active((GtkToggleButton *)pm->disablef10_checkbox);
+ terminal->setting->scrollback = gtk_spin_button_get_value_as_int(widget);
+ terminal_settings_apply_to_all(terminal);
}
-TabWidget *lxterminal_preferences_page_new(TabGroup *tabgroup)
+/* Handler for "toggled" signal on Hide Scroll Bar toggle button. */
+static void preferences_dialog_hide_scroll_bar_toggled_event(GtkToggleButton * widget, LXTerminal * terminal)
{
- TabWidget *tab;
-
- tab = g_new0(TabWidget, 1);
-
- /* create container without window */
- tab->page = gtk_event_box_new();
- GTK_WIDGET_SET_FLAGS(tab->page, GTK_NO_WINDOW);
-
- /* Sets the border width of the container. */
- gtk_container_set_border_width(GTK_CONTAINER(tab->page), 10);
-
- /* create container for label */
- tab->label_box = gtk_hbox_new(FALSE, 4);
-
- /* create icon */
- /* tab->icon = gtk_image_new_from_file(tabgroup->icon); */
-
- /* create label */
- tab->label = gtk_label_new(_(tabgroup->name));
- gtk_misc_set_alignment(GTK_MISC(tab->label), 0.0, 0.5);
- gtk_misc_set_padding(GTK_MISC(tab->label), 2, 2);
-
- /* add all of widgets to label box */
- /* gtk_box_pack_start(GTK_BOX(tab->label_box), tab->icon, FALSE, FALSE, 0); */
- gtk_box_pack_start(GTK_BOX(tab->label_box), tab->label, FALSE, FALSE, 0);
-
- gtk_widget_show_all(tab->label_box);
-
- return tab;
+ terminal->setting->hide_scroll_bar = gtk_toggle_button_get_active(widget);
+ terminal_settings_apply_to_all(terminal);
}
-void lxterminal_preferences_page_init(Prefer *prefer)
+/* Handler for "toggled" signal on Hide Menu Bar toggle button. */
+static void preferences_dialog_hide_menu_bar_toggled_event(GtkToggleButton * widget, LXTerminal * terminal)
{
- TabWidget *tab;
- int i;
-
- /* initializing all of tabs */
- for (i=0;i<G_N_ELEMENTS(tabs);i++) {
- tab = lxterminal_preferences_page_new(&tabs[i]);
- tabs[i].constructor(prefer, tab);
-
- /* add to Array */
- g_ptr_array_add(prefer->tab, tab);
-
- /* add to gtknotebook */
- gtk_notebook_append_page(GTK_NOTEBOOK(prefer->notebook), tab->page, tab->label_box);
- }
+ terminal->setting->hide_menu_bar = gtk_toggle_button_get_active(widget);
+ terminal_settings_apply_to_all(terminal);
}
-void lxterminal_preferences_free(gpointer prefer_p, GObject * where_the_object_was)
+/* Handler for "toggled" signal on Hide Close Button toggle button. */
+static void preferences_dialog_hide_close_button_toggled_event(GtkToggleButton * widget, LXTerminal * terminal)
{
- Prefer * prefer = (Prefer *) prefer_p;
- TabWidget *tab;
- int i;
-
- for (i=0;i<prefer->tab->len;i++) {
- tab = g_ptr_array_index(prefer->tab, i);
- tabs[i].destructor(prefer, tab);
+ terminal->setting->hide_close_button = gtk_toggle_button_get_active(widget);
+ terminal_settings_apply_to_all(terminal);
+}
- g_free(tab);
- }
+/* Handler for "focus-out-event" on Selection Characters entry. */
+static gboolean preferences_dialog_selection_focus_out_event(GtkWidget * widget, GdkEventFocus * event, LXTerminal * terminal)
+{
+ const gchar * new_text = gtk_entry_get_text(GTK_ENTRY(widget));
+ g_free(terminal->setting->word_selection_characters);
+ terminal->setting->word_selection_characters = g_strdup(new_text);
+ terminal_settings_apply_to_all(terminal);
+ return FALSE;
+}
- g_ptr_array_free(prefer->tab, TRUE);
- gtk_widget_destroy(prefer->dialog);
- g_free(prefer);
+/* Handler for "toggled" signal on Disable F10 toggle button. */
+static void preferences_dialog_disable_f10_toggled_event(GtkToggleButton * widget, LXTerminal * terminal)
+{
+ terminal->setting->disable_f10 = gtk_toggle_button_get_active(widget);
+ terminal_settings_apply_to_all(terminal);
}
-void lxterminal_preferences_on_response(GtkDialog* dlg, gint response, Prefer *prefer)
+/* Convert the user preference on tab position, expressed as a string, to the internal representation.
+ * These have to match the order in the .glade file. */
+gint terminal_tab_get_position_id(gchar * position)
{
- gint i;
- TabWidget *tab;
-
- if(G_LIKELY(response == GTK_RESPONSE_OK)) {
- for (i=0;i<prefer->tab->len;i++) {
- tab = g_ptr_array_index(prefer->tab, i);
- tabs[i].save(prefer, tab);
- }
-
- /* saving perferences */
- setting_save(prefer->terminal->setting);
-
- /* update NOW! */
- /* update all terminals in all windows */
- g_ptr_array_foreach(prefer->terminal->parent->windows,
- (GFunc) terminal_setting_update,
- prefer->terminal->setting);
- }
-
- gtk_widget_destroy((GtkWidget *)dlg);
+ if (strcmp(position, "bottom") == 0)
+ return 1;
+ else if (strcmp(position, "left") == 0)
+ return 2;
+ else if (strcmp(position, "right") == 0)
+ return 3;
+ else
+ return 0;
}
-void lxterminal_preferences_dialog(GtkAction *action, gpointer data)
+/* Initialize and display the preferences dialog. */
+void terminal_preferences_dialog(GtkAction * action, LXTerminal * terminal)
{
- LXTerminal *terminal = (LXTerminal *)data;
- Prefer *prefer;
- GtkWidget *pdialog;
- GtkWidget *tab;
-
- prefer = g_new0(Prefer, 1);
- prefer->terminal = terminal;
- prefer->tab = g_ptr_array_new();
-
- /* create window */
- prefer->dialog = gtk_dialog_new_with_buttons(_("Preferences"),
- NULL,
- GTK_DIALOG_NO_SEPARATOR,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OK, GTK_RESPONSE_OK,
- NULL );
- gtk_dialog_set_alternative_button_order((GtkDialog *)prefer->dialog, GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
- gtk_dialog_set_default_response((GtkDialog *)prefer->dialog, GTK_RESPONSE_OK);
- gtk_window_set_position(GTK_WINDOW(prefer->dialog), GTK_WIN_POS_CENTER);
-
- /* g_signal */
- g_signal_connect(prefer->dialog, "response", G_CALLBACK(lxterminal_preferences_on_response), prefer);
- g_object_weak_ref((GObject *)prefer->dialog, lxterminal_preferences_free, prefer);
-
- /* create notebook */
- prefer->notebook = gtk_notebook_new();
- gtk_notebook_set_scrollable(GTK_NOTEBOOK(prefer->notebook), TRUE);
- gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefer->notebook), TRUE);
- gtk_box_pack_start(GTK_BOX(((GtkDialog *)prefer->dialog)->vbox), prefer->notebook, FALSE, FALSE, 0);
-
- /* initializing pages */
- lxterminal_preferences_page_init(prefer);
-
- gtk_widget_show_all(prefer->dialog);
+ Setting * setting = terminal->setting;
+
+ GtkBuilder * builder = gtk_builder_new();
+ if ( ! gtk_builder_add_from_file(builder, PACKAGE_DATA_DIR "/lxterminal/lxterminal-preferences.ui", NULL))
+ {
+ g_object_unref(builder);
+ return;
+ }
+
+ GtkWidget * dialog = GTK_WIDGET(gtk_builder_get_object(builder, "lxterminal_preferences"));
+ gtk_window_set_title(GTK_WINDOW(dialog), _("LXTerminal"));
+ gtk_window_set_icon_from_file(GTK_WINDOW(dialog), PACKAGE_DATA_DIR "/pixmaps/lxterminal.png", NULL);
+ g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(preferences_dialog_response_event), terminal);
+
+ GtkWidget * w = GTK_WIDGET(gtk_builder_get_object(builder, "terminal_font"));
+ gtk_font_button_set_font_name(GTK_FONT_BUTTON(w), setting->font_name);
+ g_signal_connect(G_OBJECT(w), "font-set", G_CALLBACK(preferences_dialog_font_set_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "background_color"));
+ gtk_color_button_set_color(GTK_COLOR_BUTTON(w), &setting->background_color);
+ gtk_color_button_set_alpha(GTK_COLOR_BUTTON(w), setting->background_alpha);
+ g_signal_connect(G_OBJECT(w), "color-set", G_CALLBACK(preferences_dialog_background_color_set_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "foreground_color"));
+ gtk_color_button_set_color(GTK_COLOR_BUTTON(w), &setting->foreground_color);
+ g_signal_connect(G_OBJECT(w), "color-set", G_CALLBACK(preferences_dialog_foreground_color_set_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "allow_bold"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), ! setting->disallow_bold);
+ g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(preferences_dialog_allow_bold_toggled_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "cursor_blink"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), setting->cursor_blink);
+ g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(preferences_dialog_cursor_blink_toggled_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "cursor_style_block"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), ! setting->cursor_underline);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "cursor_style_underline"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), setting->cursor_underline);
+ g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(preferences_dialog_cursor_underline_toggled_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "audible_bell"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), setting->audible_bell);
+ g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(preferences_dialog_audible_bell_toggled_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "tab_position"));
+ gtk_combo_box_set_active(GTK_COMBO_BOX(w), terminal_tab_get_position_id(setting->tab_position));
+ g_signal_connect(G_OBJECT(w), "changed", G_CALLBACK(preferences_dialog_tab_position_changed_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "scrollback_lines"));
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), setting->scrollback);
+ g_signal_connect(G_OBJECT(w), "value-changed", G_CALLBACK(preferences_dialog_scrollback_value_changed_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "hide_scroll_bar"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), setting->hide_scroll_bar);
+ g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(preferences_dialog_hide_scroll_bar_toggled_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "hide_menu_bar"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), setting->hide_menu_bar);
+ g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(preferences_dialog_hide_menu_bar_toggled_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "hide_close_button"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), setting->hide_close_button);
+ g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(preferences_dialog_hide_close_button_toggled_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "select_by_word"));
+ gtk_entry_set_text(GTK_ENTRY(w), setting->word_selection_characters);
+ g_signal_connect(G_OBJECT(w), "focus-out-event", G_CALLBACK(preferences_dialog_selection_focus_out_event), terminal);
+
+ w = GTK_WIDGET(gtk_builder_get_object(builder, "disable_f10"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), setting->disable_f10);
+ g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(preferences_dialog_disable_f10_toggled_event), terminal);
+
+ gtk_widget_show_all(dialog);
+ g_object_unref(builder);
}
diff --git a/src/preferences.h b/src/preferences.h
index 6f86315..f1665e7 100644
--- a/src/preferences.h
+++ b/src/preferences.h
@@ -1,61 +1,27 @@
+/**
+ * Copyright 2008 Fred Chien <cfsghost@gmail.com>
+ * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
#ifndef LXTERMINAL_PREFERENCES_H
#define LXTERMINAL_PREFERENCES_H
-typedef struct {
- GtkWidget *label_box;
- GtkWidget *icon;
- GtkWidget *label;
- GtkWidget *page;
- void *childs;
-} TabWidget;
-
-typedef struct {
- LXTerminal *terminal;
- GtkWidget *dialog;
- GtkWidget *notebook;
- GPtrArray *tab;
-} Prefer;
-
-typedef struct {
- gchar *name;
- gchar *icon;
- void (*constructor)(Prefer *prefer, TabWidget *tab);
- void (*destructor)(Prefer *prefer, TabWidget *tab);
- void (*save)(Prefer *prefer, TabWidget *tab);
-} TabGroup;
-
-typedef struct {
- GtkWidget *box;
- GtkWidget *font_label;
- GtkWidget *font_button;
- GtkWidget *bgcolor_label;
- GtkWidget *bgcolor_entry;
- GtkWidget *fgcolor_label;
- GtkWidget *fgcolor_entry;
- GtkWidget *cursorblinks_label;
- GtkWidget *cursorblinks_checkbox;
-} PreferStyle;
-
-typedef struct {
- GtkWidget *box;
- GtkWidget *tabpos_label;
- GtkWidget *tabpos_combobox;
- GtkWidget *scrollback_label;
- GtkWidget *scrollback_entry;
- GtkWidget *hidescrollbar_label;
- GtkWidget *hidescrollbar_checkbox;
- GtkWidget *hidemenubar_label;
- GtkWidget *hidemenubar_checkbox;
-} PreferDisplay;
-
-typedef struct {
- GtkWidget *box;
- GtkWidget *selchars_label;
- GtkWidget *selchars_entry;
- GtkWidget *disablef10_label;
- GtkWidget *disablef10_checkbox;
-} PreferMisc;
-
-void lxterminal_preferences_dialog(GtkAction *action, gpointer data);
+extern void terminal_preferences_dialog(GtkAction * action, LXTerminal * terminal);
+extern gint terminal_tab_get_position_id(gchar * position);
#endif
diff --git a/src/setting.c b/src/setting.c
index f4a3187..7c225b9 100644
--- a/src/setting.c
+++ b/src/setting.c
@@ -1,5 +1,6 @@
-/*
+/**
* Copyright 2008 Fred Chien <cfsghost@gmail.com>
+ * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
*
* 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
@@ -20,121 +21,106 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
#include "setting.h"
-void setting_save_to_file(const char *path, const char *data)
+/* Save settings to configuration file. */
+void setting_save(Setting * setting)
{
- FILE *fp;
-
- if (!g_file_test(path, G_FILE_TEST_EXISTS))
- g_creat(path, 0700);
-
- /* open config file */
- fp = fopen(path, "w");
- if (fp != NULL)
- {
- fputs(data, fp);
- fclose(fp);
- }
+ /* Push settings to GKeyFile. */
+ g_key_file_set_string(setting->keyfile, "general", "fontname", setting->font_name);
+ gchar * p = gdk_color_to_string(&setting->background_color);
+ if (p != NULL)
+ g_key_file_set_string(setting->keyfile, "general", "bgcolor", p);
+ g_free(p);
+ g_key_file_set_integer(setting->keyfile, "general", "bgalpha", setting->background_alpha);
+ p = gdk_color_to_string(&setting->foreground_color);
+ if (p != NULL)
+ g_key_file_set_string(setting->keyfile, "general", "fgcolor", p);
+ g_free(p);
+ g_key_file_set_boolean(setting->keyfile, "general", "disallowbold", setting->disallow_bold);
+ g_key_file_set_boolean(setting->keyfile, "general", "cursorblinks", setting->cursor_blink);
+ g_key_file_set_boolean(setting->keyfile, "general", "cursorunderline", setting->cursor_underline);
+ g_key_file_set_boolean(setting->keyfile, "general", "audiblebell", setting->audible_bell);
+ g_key_file_set_string(setting->keyfile, "general", "tabpos", setting->tab_position);
+ g_key_file_set_integer(setting->keyfile, "general", "scrollback", setting->scrollback);
+ g_key_file_set_boolean(setting->keyfile, "general", "hidescrollbar", setting->hide_scroll_bar);
+ g_key_file_set_boolean(setting->keyfile, "general", "hidemenubar", setting->hide_menu_bar);
+ g_key_file_set_boolean(setting->keyfile, "general", "hideclosebutton", setting->hide_close_button);
+ g_key_file_set_string(setting->keyfile, "general", "selchars", setting->word_selection_characters);
+ g_key_file_set_boolean(setting->keyfile, "general", "disablef10", setting->disable_f10);
+
+ /* Convert GKeyFile to text and build path to configuration file. */
+ gchar * file_data = g_key_file_to_data(setting->keyfile, NULL, NULL);
+ gchar * path = g_build_filename(g_get_user_config_dir(), "lxterminal/lxterminal.conf", NULL);
+
+ if ((file_data != NULL) && (path != NULL))
+ {
+ /* Create the file if necessary. */
+ int fd = open(path, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ g_warning("Configuration file create failed: %s\n", g_strerror(errno));
+ else
+ {
+ write(fd, file_data, strlen(file_data));
+ close(fd);
+ }
+ }
+
+ /* Deallocate memory. */
+ g_free(file_data);
+ g_free(path);
}
-void setting_save(Setting *setting)
+/* Load settings from configuration file. */
+Setting * load_setting_from_file(const char * filename)
{
- gchar *path;
- gchar *file_data;
-
- /* build config path */
- path = g_build_filename(g_get_user_config_dir(), "lxterminal/lxterminal.conf", NULL);
-
- /* push settings to GKeyFile */
- g_key_file_set_string(setting->keyfile, "general", "fontname", setting->fontname);
- g_key_file_set_string(setting->keyfile, "general", "selchars", setting->selchars);
- g_key_file_set_string(setting->keyfile, "general", "bgcolor", setting->bgcolor);
- g_key_file_set_integer(setting->keyfile, "general", "bgalpha", setting->bgalpha);
- g_key_file_set_string(setting->keyfile, "general", "fgcolor", setting->fgcolor);
- g_key_file_set_string(setting->keyfile, "general", "tabpos", setting->tabpos);
- g_key_file_set_integer(setting->keyfile, "general", "scrollback", (gint)setting->scrollback);
- g_key_file_set_boolean(setting->keyfile, "general", "disablef10", setting->disablef10);
- g_key_file_set_boolean(setting->keyfile, "general", "hidemenubar", setting->hidemenubar);
- g_key_file_set_boolean(setting->keyfile, "general", "hidescrollbar", setting->hidescrollbar);
- g_key_file_set_boolean(setting->keyfile, "general", "cursorblinks", setting->cursorblinks);
-
- /* generate config data */
- file_data = g_key_file_to_data(setting->keyfile, NULL, NULL);
-
- /* save to config file */
- setting_save_to_file(path, file_data);
-
- /* release */
- g_free(file_data);
-}
-
-Setting *load_setting_from_file(const char *filename)
-{
- GKeyFileFlags flags;
- GError *error = NULL;
- Setting *setting;
-
- setting = (Setting *)malloc(sizeof(Setting));
-
- /* initiate key_file */
- setting->keyfile = g_key_file_new();
- flags = G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS;
-
- /* Load config */
- if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
- if (!g_key_file_load_from_file(setting->keyfile, filename, flags, &error))
- goto setting_default;
-
- /* general setting */
- setting->fontname = g_key_file_get_string(setting->keyfile, "general", "fontname", NULL);
- setting->selchars = g_key_file_get_string(setting->keyfile, "general", "selchars", NULL);
- setting->bgcolor = g_key_file_get_string(setting->keyfile, "general", "bgcolor", NULL);
- setting->bgalpha = g_key_file_get_integer(setting->keyfile, "general", "bgalpha", NULL);
- setting->fgcolor = g_key_file_get_string(setting->keyfile, "general", "fgcolor", NULL);
- setting->tabpos = g_key_file_get_string(setting->keyfile, "general", "tabpos", NULL);
- setting->scrollback = (glong)g_key_file_get_integer(setting->keyfile, "general", "scrollback", NULL);
- setting->disablef10 = g_key_file_get_boolean(setting->keyfile, "general", "disablef10", NULL);
- setting->hidemenubar = g_key_file_get_boolean(setting->keyfile, "general", "hidemenubar", NULL);
- setting->hidescrollbar = g_key_file_get_boolean(setting->keyfile, "general", "hidescrollbar", NULL);
- setting->cursorblinks = g_key_file_get_boolean(setting->keyfile, "general", "cursorblinks", NULL);
- }
-
-setting_default:
-
- if (!setting->fontname)
- setting->fontname = g_strdup("monospace 10");
-
- if (!setting->selchars)
- setting->selchars = g_strdup("-A-Za-z0-9,./?%&#:_");
-
- if (!setting->bgcolor)
- setting->bgcolor = g_strdup("#000000");
-
- if (!setting->bgalpha)
- setting->bgalpha = (guint16) 0xFFFF;
-
- if (!setting->fgcolor)
- setting->fgcolor = g_strdup("#aaaaaa");
-
- if (!setting->tabpos)
- setting->tabpos = g_strdup("top");
-
- if (!setting->scrollback)
- setting->scrollback = (glong)1000;
-
- if (!setting->disablef10)
- setting->disablef10 = FALSE;
-
- if (!setting->hidemenubar)
- setting->hidemenubar = FALSE;
-
- if (!setting->hidescrollbar)
- setting->hidescrollbar = FALSE;
-
- if (!setting->cursorblinks)
- setting->cursorblinks = FALSE;
-
- return setting;
+ /* Allocate structure. */
+ Setting * setting = g_new0(Setting, 1);
+
+ /* Initialize nonzero integer values to defaults. */
+ setting->background_alpha = 65535;
+ setting->foreground_color.red = setting->foreground_color.green = setting->foreground_color.blue = 0xaaaa;
+
+ /* Load configuration. */
+ setting->keyfile = g_key_file_new();
+ GError * error = NULL;
+ if ((g_file_test(filename, G_FILE_TEST_EXISTS))
+ && (g_key_file_load_from_file(setting->keyfile, filename, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &error)))
+ {
+ setting->font_name = g_key_file_get_string(setting->keyfile, "general", "fontname", NULL);
+ char * p = g_key_file_get_string(setting->keyfile, "general", "bgcolor", NULL);
+ if (p != NULL)
+ gdk_color_parse(p, &setting->background_color);
+ setting->background_alpha = g_key_file_get_integer(setting->keyfile, "general", "bgalpha", NULL);
+ p = g_key_file_get_string(setting->keyfile, "general", "fgcolor", NULL);
+ if (p != NULL)
+ gdk_color_parse(p, &setting->foreground_color);
+ setting->disallow_bold = g_key_file_get_boolean(setting->keyfile, "general", "disallowbold", NULL);
+ setting->cursor_blink = g_key_file_get_boolean(setting->keyfile, "general", "cursorblinks", NULL);
+ setting->cursor_underline = g_key_file_get_boolean(setting->keyfile, "general", "cursorunderline", NULL);
+ setting->audible_bell = g_key_file_get_boolean(setting->keyfile, "general", "audiblebell", NULL);
+ setting->tab_position = g_key_file_get_string(setting->keyfile, "general", "tabpos", NULL);
+ setting->scrollback = g_key_file_get_integer(setting->keyfile, "general", "scrollback", NULL);
+ setting->hide_scroll_bar = g_key_file_get_boolean(setting->keyfile, "general", "hidescrollbar", NULL);
+ setting->hide_menu_bar = g_key_file_get_boolean(setting->keyfile, "general", "hidemenubar", NULL);
+ setting->hide_close_button = g_key_file_get_boolean(setting->keyfile, "general", "hideclosebutton", NULL);
+ setting->word_selection_characters = g_key_file_get_string(setting->keyfile, "general", "selchars", NULL);
+ setting->disable_f10 = g_key_file_get_boolean(setting->keyfile, "general", "disablef10", NULL);
+ }
+
+ /* Default configuration strings. */
+ if (setting->font_name == NULL)
+ setting->font_name = g_strdup("monospace 10");
+ if (setting->tab_position == NULL)
+ setting->tab_position = g_strdup("top");
+ if (setting->word_selection_characters == NULL)
+ setting->word_selection_characters = g_strdup("-A-Za-z0-9,./?%&#:_");
+ return setting;
}
diff --git a/src/setting.h b/src/setting.h
index 7ae28b1..f10e904 100644
--- a/src/setting.h
+++ b/src/setting.h
@@ -1,21 +1,53 @@
+/**
+ * Copyright 2008 Fred Chien <cfsghost@gmail.com>
+ * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
#ifndef LXTERMINAL_SETTING_H
#define LXTERMINAL_SETTING_H
+#include <gtk/gtk.h>
+
+/* User preferences. */
typedef struct _setting {
- char *fontname;
- char *selchars;
- char *bgcolor;
- char *fgcolor;
- char *tabpos;
- guint16 bgalpha;
- glong scrollback;
- gboolean disablef10;
- GKeyFile *keyfile;
- gboolean hidemenubar;
- gboolean hidescrollbar;
- gboolean cursorblinks;
+
+ GKeyFile * keyfile; /* Pointer to GKeyFile containing settings */
+ char * font_name; /* Font name */
+ GdkColor background_color; /* Background color */
+ guint16 background_alpha; /* Alpha value to go with background color */
+ GdkColor foreground_color; /* Foreground color */
+ gboolean disallow_bold; /* Disallow bolding by VTE */
+ gboolean cursor_blink; /* True if cursor blinks */
+ gboolean cursor_underline; /* True if underline cursor; false if block cursor */
+ gboolean audible_bell; /* True if audible bell */
+ char * tab_position; /* Position of tabs on main window (top, bottom, left, right) */
+ gint scrollback; /* Scrollback buffer size in lines */
+ gboolean hide_scroll_bar; /* True if scroll bar is NOT visible */
+ gboolean hide_menu_bar; /* True if menu bar is NOT visible */
+ gboolean hide_close_button; /* True if close buttons are NOT visible */
+ char * word_selection_characters; /* Characters that act as word breaks during selection by word */
+ gboolean disable_f10; /* True if F10 will be passed to program; false if it brings up File menu */
+
+ gboolean geometry_change; /* True if there is a geometry change, until it has been acted on */
+
} Setting;
-Setting *load_setting_from_file(const char *filename);
+extern void setting_save(Setting * setting);
+extern Setting * load_setting_from_file(const char * filename);
#endif
diff --git a/src/tab.c b/src/tab.c
index 4745bcd..11f44c8 100644
--- a/src/tab.c
+++ b/src/tab.c
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright 2008 Fred Chien <cfsghost@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -24,83 +24,55 @@
#include "lxterminal.h"
#include "tab.h"
-void lxterminal_tab_set_position(GtkWidget *notebook, gint tabpos)
+/* Set the "clicked" signal handler on a tab. */
+void lxterminal_tab_label_close_button_clicked(GCallback func, Term * term)
{
- switch(tabpos) {
- case 0:
- gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
- break;
- case 1:
- gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM);
- break;
- case 2:
- gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
- break;
- default:
- gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_RIGHT);
- }
+ g_signal_connect(G_OBJECT(term->label->close_btn), "clicked", func, term);
}
-gint lxterminal_tab_get_position_id(gchar *position)
+/* Set the label on a tab. */
+void lxterminal_tab_label_set_text(LXTab * tab, const gchar * str)
{
- if (strcmp(position, "top")==0)
- return 0;
- else if (strcmp(position, "bottom")==0)
- return 1;
- else if (strcmp(position, "left")==0)
- return 2;
- else
- return 3;
+ gtk_label_set_text(GTK_LABEL(tab->label), str);
}
-void lxterminal_tab_label_close_button_clicked(GCallback func, Term *term)
+/* Set the tooltip on a tab. */
+void lxterminal_tab_label_set_tooltip_text(LXTab * tab, const gchar * str)
{
- g_signal_connect(term->label->close_btn, "clicked", func, term);
+ gtk_widget_set_tooltip_text(tab->label, str);
}
-void lxterminal_tab_label_set_text(LXTab *tab, const gchar *str)
+/* Create a new tab. */
+LXTab * lxterminal_tab_label_new(const gchar * str)
{
- gtk_label_set_text((GtkLabel *)tab->label, str);
-}
-
-void lxterminal_tab_label_set_tooltip_text(LXTab *tab, const gchar *str)
-{
- gtk_widget_set_tooltip_text(tab->label, str);
-}
-
-LXTab *lxterminal_tab_label_new(const gchar *str)
-{
- LXTab *tab;
- GtkRcStyle *rcstyle;
-
- tab = malloc(sizeof(LXTab));
-
- tab->main = gtk_hbox_new(FALSE, 4);
-
- /* create button */
- tab->close_btn = gtk_button_new();
- gtk_button_set_relief(GTK_BUTTON(tab->close_btn), GTK_RELIEF_NONE);
- gtk_button_set_focus_on_click(GTK_BUTTON(tab->close_btn), FALSE);
- gtk_container_add(GTK_CONTAINER(tab->close_btn), gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU));
-
- /* make button as small as possible */
- rcstyle = gtk_rc_style_new();
- rcstyle->xthickness = rcstyle->ythickness = 0;
- gtk_widget_modify_style(tab->close_btn, rcstyle);
- gtk_rc_style_unref(rcstyle),
-
- /* create label for tab */
- tab->label = gtk_label_new(str);
- gtk_widget_set_size_request(GTK_WIDGET(tab->label), 100, -1);
- gtk_label_set_ellipsize(GTK_LABEL(tab->label), PANGO_ELLIPSIZE_END);
- gtk_misc_set_alignment(GTK_MISC(tab->label), 0.0, 0.5);
- gtk_misc_set_padding(GTK_MISC(tab->label), 0, 0);
-
- gtk_box_pack_start(GTK_BOX(tab->main), tab->label, TRUE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX(tab->main), gtk_label_new(""), TRUE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX(tab->main), tab->close_btn, FALSE, FALSE, 0);
-
- gtk_widget_show_all(tab->main);
-
- return tab;
+ /* Allocate LXTab structure. */
+ LXTab * tab = g_new0(LXTab, 1);
+
+ /* Create a horizontal box as the toplevel. */
+ tab->main = gtk_hbox_new(FALSE, 4);
+
+ /* Create the Close button. */
+ tab->close_btn = gtk_button_new();
+ gtk_button_set_relief(GTK_BUTTON(tab->close_btn), GTK_RELIEF_NONE);
+ gtk_button_set_focus_on_click(GTK_BUTTON(tab->close_btn), FALSE);
+ gtk_container_add(GTK_CONTAINER(tab->close_btn), gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU));
+
+ /* Make the button as small as possible. */
+ GtkRcStyle * rcstyle = gtk_rc_style_new();
+ rcstyle->xthickness = rcstyle->ythickness = 0;
+ gtk_widget_modify_style(tab->close_btn, rcstyle);
+ gtk_rc_style_unref(rcstyle),
+
+ /* Create the label. */
+ tab->label = gtk_label_new(str);
+ gtk_widget_set_size_request(GTK_WIDGET(tab->label), 100, -1);
+ gtk_label_set_ellipsize(GTK_LABEL(tab->label), PANGO_ELLIPSIZE_END);
+ gtk_misc_set_alignment(GTK_MISC(tab->label), 0.0, 0.5);
+ gtk_misc_set_padding(GTK_MISC(tab->label), 0, 0);
+
+ /* Pack everything, show the widget and return. */
+ gtk_box_pack_start(GTK_BOX(tab->main), tab->label, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(tab->main), tab->close_btn, FALSE, FALSE, 0);
+ gtk_widget_show_all(tab->main);
+ return tab;
}
diff --git a/src/tab.h b/src/tab.h
index 129ab2b..d36ac90 100644
--- a/src/tab.h
+++ b/src/tab.h
@@ -1,12 +1,33 @@
+/**
+ * Copyright 2008 Fred Chien <cfsghost@gmail.com>
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
#ifndef LXTERMINAL_TAB_H
#define LXTERMINAL_TAB_H
#include "lxterminal.h"
-void lxterminal_tab_label_close_button_clicked(GCallback func, Term *term);
-void lxterminal_tab_label_set_text(LXTab *tab, const gchar *str);
-void lxterminal_tab_label_set_tooltip_text(LXTab *tab, const gchar *str);
-LXTab *lxterminal_tab_label_new(const gchar *str);
+extern void lxterminal_tab_set_position(GtkWidget * notebook, gint tabpos);
+extern gint lxterminal_tab_get_position_id(gchar * position);
+extern void lxterminal_tab_label_close_button_clicked(GCallback func, Term * term);
+extern void lxterminal_tab_label_set_text(LXTab * tab, const gchar * str);
+extern void lxterminal_tab_label_set_tooltip_text(LXTab * tab, const gchar * str);
+extern LXTab * lxterminal_tab_label_new(const gchar * str);
#endif
diff --git a/src/unixsocket.c b/src/unixsocket.c
index b6ca767..88f6e18 100644
--- a/src/unixsocket.c
+++ b/src/unixsocket.c
@@ -1,5 +1,6 @@
-/*
+/**
* Copyright 2008 Fred Chien <cfsghost@gmail.com>
+ * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
*
* 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
@@ -17,7 +18,6 @@
* MA 02110-1301, USA.
*/
-#include <sys/time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
@@ -25,172 +25,215 @@
#include <errno.h>
#include <glib.h>
#include <gtk/gtk.h>
-#include <glib/gi18n.h>
#include "lxterminal.h"
#include "unixsocket.h"
-static gboolean
-lxterminal_socket_read_channel(GIOChannel *gio, GIOCondition condition, gpointer lxtermwin)
-{
- GIOStatus ret;
- GError *err = NULL;
- gchar *msg;
- gsize len;
- gsize term;
-
- /* read messages */
- ret = g_io_channel_read_line(gio, &msg, &len, &term, &err);
- if (ret == G_IO_STATUS_ERROR)
- g_error("Error reading: %s\n", err->message);
-
- if (len > 0) {
- gchar **argv;
- gint argc;
-
- msg[term] = '\0';
-
- /* generate args */
- g_shell_parse_argv(msg, &argc, &argv, NULL);
+static gboolean lxterminal_socket_read_channel(GIOChannel * gio, GIOCondition condition, LXTermWindow * lxtermwin);
+static gboolean lxterminal_socket_accept_client(GIOChannel * source, GIOCondition condition, LXTermWindow * lxtermwin);
- /* initializing LXTerminal and create a new window */
- lxterminal_init(lxtermwin, argc, argv, ((LXTermWindow *) lxtermwin)->setting);
-
- /* release */
- g_strfreev(argv);
- }
- g_free(msg);
-
- if (condition & G_IO_HUP)
- return FALSE;
-
- return TRUE;
+/* Handler for successful read on communication socket. */
+static gboolean lxterminal_socket_read_channel(GIOChannel * gio, GIOCondition condition, LXTermWindow * lxtermwin)
+{
+ /* Read message. */
+ gchar * msg = NULL;
+ gsize len = 0;
+ gsize term = 0;
+ GError * err = NULL;
+ GIOStatus ret = g_io_channel_read_line(gio, &msg, &len, &term, &err);
+ if (ret == G_IO_STATUS_ERROR)
+ g_warning("Error reading socket: %s\n", err->message);
+
+ /* Process message. */
+ if (len > 0)
+ {
+ /* Overwrite the line termination with a NUL. */
+ msg[term] = '\0';
+
+ /* Parse arguments.
+ * Initialize a new LXTerminal and create a new window. */
+ gint argc;
+ gchar * * argv;
+ g_shell_parse_argv(msg, &argc, &argv, NULL);
+ CommandArguments arguments;
+ lxterminal_process_arguments(argc, argv, &arguments);
+ lxterminal_initialize(lxtermwin, &arguments, lxtermwin->setting);
+ g_strfreev(argv);
+ }
+ g_free(msg);
+
+ /* If there was a disconnect, discontinue read. Otherwise, continue. */
+ if (condition & G_IO_HUP)
+ return FALSE;
+ return TRUE;
}
-static gboolean
-lxterminal_socket_accept_client(GIOChannel *source, GIOCondition condition, gpointer lxtermwin)
+/* Handler for successful listen on communication socket. */
+static gboolean lxterminal_socket_accept_client(GIOChannel * source, GIOCondition condition, LXTermWindow * lxtermwin)
{
- if (condition & G_IO_IN) {
- GIOChannel *gio;
- int fd;
- int flags;
-
- /* new connection */
- fd = accept(g_io_channel_unix_get_fd(source), NULL, NULL);
- if (fd < 0)
- g_error("Accept failed: %s\n", g_strerror(errno));
-
- flags = fcntl(fd, F_GETFL, 0);
- fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-
- gio = g_io_channel_unix_new(fd);
- if (!gio)
- g_error("Cannot create new GIOChannel!\n");
-
- g_io_channel_set_encoding(gio, NULL, NULL);
-
- g_io_add_watch(gio, G_IO_IN | G_IO_HUP, lxterminal_socket_read_channel, lxtermwin);
-
- g_io_channel_unref(gio);
- }
-
- /* our listener socket hung up - we are dead */
- if (condition & G_IO_HUP)
- g_error("Server listening socket died!\n");
-
- return TRUE;
+ if (condition & G_IO_IN)
+ {
+ /* Accept the new connection. */
+ int fd = accept(g_io_channel_unix_get_fd(source), NULL, NULL);
+ if (fd < 0)
+ g_warning("Accept failed: %s\n", g_strerror(errno));
+
+ /* Add O_NONBLOCK to the flags. */
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+
+ /* Create a glib I/O channel. */
+ GIOChannel * gio = g_io_channel_unix_new(fd);
+ if (gio == NULL)
+ g_warning("Cannot create new GIOChannel\n");
+ else
+ {
+ /* Set up the glib I/O channel and add it to the event loop. */
+ g_io_channel_set_encoding(gio, NULL, NULL);
+ g_io_add_watch(gio, G_IO_IN | G_IO_HUP, (GIOFunc) lxterminal_socket_read_channel, lxtermwin);
+ g_io_channel_unref(gio);
+ }
+ }
+
+ /* Our listening socket hung up - we are dead. */
+ if (condition & G_IO_HUP)
+ g_error("Server listening socket closed unexpectedly\n");
+
+ return TRUE;
}
-gboolean
-lxterminal_socket_init(LXTermWindow *lxtermwin, int argc, char **argv)
+gboolean lxterminal_socket_initialize(LXTermWindow * lxtermwin, CommandArguments * arguments)
{
- struct sockaddr_un skaddr;
- GIOChannel *gio;
- int skfd;
- gchar *socket_path;
-
- socket_path = g_strdup_printf("/tmp/.lxterminal-socket%s-%s", gdk_get_display(), g_get_user_name());
-
- /* create socket */
- skfd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (skfd < 0) {
- if (g_file_test(socket_path, G_FILE_TEST_EXISTS)) {
- unlink(socket_path);
- }
-
- skfd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (skfd < 0)
- g_error("Cannot create socket!");
- }
-
- /* Initiate socket */
- bzero(&skaddr, sizeof(skaddr));
-
- /* setting UNIX socket */
- skaddr.sun_family = AF_UNIX;
- snprintf(skaddr.sun_path, sizeof(skaddr.sun_path), "%s", socket_path);
-
- /* try to connect to current LXTerminal */
- if (connect(skfd, (struct sockaddr *)&skaddr, sizeof(skaddr)) < 0) {
- unlink(socket_path);
-
- /* bind to socket */
- if (bind(skfd, (struct sockaddr *)&skaddr, sizeof(skaddr)) < 0)
- g_error("Bind on socket failed: %s\n", g_strerror(errno));
-
- /* listen on socket */
- if (listen(skfd, 5) < 0)
- g_error("Listen on socket failed: %s\n", g_strerror(errno));
-
- /* create I/O channel */
- gio = g_io_channel_unix_new(skfd);
- if (!gio)
- g_error("Cannot create new GIOChannel!\n");
-
- /* setting encoding */
- g_io_channel_set_encoding(gio, NULL, NULL);
- g_io_channel_set_buffered(gio, FALSE);
- g_io_channel_set_close_on_unref(gio, TRUE);
-
- /* I/O channel into the main event loop */
- if (!g_io_add_watch(gio, G_IO_IN | G_IO_HUP, lxterminal_socket_accept_client, lxtermwin))
- g_error("Cannot add watch on GIOChannel\n");
-
- /* channel will automatically shutdown when the watch returns FALSE */
- g_io_channel_set_close_on_unref(gio, TRUE);
- g_io_channel_unref(gio);
-
- g_free(socket_path);
- return TRUE;
- } else {
- int i;
- gboolean setworkdir = FALSE;
-
- gio = g_io_channel_unix_new(skfd);
- g_io_channel_set_encoding(gio, NULL, NULL);
-
- for (i=0;i<argc;i++) {
- if (strncmp(argv[i],"--working-directory=", 20)==0) {
- setworkdir = TRUE;
- }
-
- g_io_channel_write_chars(gio, g_shell_quote(*(argv+i)), -1, NULL, NULL);
- if (i+1!=argc) {
- g_io_channel_write_chars(gio, " ", -1, NULL, NULL);
- } else {
- if (!setworkdir) {
- gchar *workdir = g_get_current_dir();
- g_io_channel_write_chars(gio, " --working-directory=", -1, NULL, NULL);
- g_io_channel_write_chars(gio, workdir, -1, NULL, NULL);
- g_free(workdir);
- }
- }
- }
-
- g_io_channel_write_chars(gio, "\n", -1, NULL, NULL);
- g_io_channel_flush(gio, NULL);
- g_io_channel_unref(gio);
- g_free(socket_path);
- return FALSE;
- }
+ /* Normally, LXTerminal uses one process to control all of its windows.
+ * The first process to start will create a Unix domain socket in /tmp.
+ * It will then bind and listen on this socket.
+ * The subsequent processes will connect to the controller that owns the Unix domain socket.
+ * They will pass their command line over the socket and exit.
+ *
+ * If for any reason both the connect and bind fail, we will fall back to having that
+ * process be standalone; it will not be either the controller or a user of the controller.
+ * This behavior was introduced in response to a problem report (2973537).
+ *
+ * This function returns TRUE if this process should keep running and FALSE if it should exit. */
+
+ /* Formulate the path for the Unix domain socket. */
+ gchar * socket_path = g_strdup_printf("/tmp/.lxterminal-socket%s-%s", gdk_get_display(), g_get_user_name());
+
+ /* Create socket. */
+ int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ {
+ g_warning("Socket create failed: %s\n", g_strerror(errno));
+ g_free(socket_path);
+ return TRUE;
+ }
+
+ /* Initialize socket address for Unix domain socket. */
+ struct sockaddr_un sock_addr;
+ memset(&sock_addr, 0, sizeof(sock_addr));
+ sock_addr.sun_family = AF_UNIX;
+ snprintf(sock_addr.sun_path, sizeof(sock_addr.sun_path), "%s", socket_path);
+
+ /* Try to connect to an existing LXTerminal process. */
+ if (connect(fd, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) < 0)
+ {
+ /* Connect failed. We are the controller, unless something fails. */
+ unlink(socket_path);
+ g_free(socket_path);
+
+ /* Bind to socket. */
+ if (bind(fd, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) < 0)
+ {
+ g_warning("Bind on socket failed: %s\n", g_strerror(errno));
+ close(fd);
+ return TRUE;
+ }
+
+ /* Listen on socket. */
+ if (listen(fd, 5) < 0)
+ {
+ g_warning("Listen on socket failed: %s\n", g_strerror(errno));
+ close(fd);
+ return TRUE;
+ }
+
+ /* Create a glib I/O channel. */
+ GIOChannel * gio = g_io_channel_unix_new(fd);
+ if (gio == NULL)
+ {
+ g_warning("Cannot create GIOChannel\n");
+ close(fd);
+ return TRUE;
+ }
+
+ /* Set up GIOChannel. */
+ g_io_channel_set_encoding(gio, NULL, NULL);
+ g_io_channel_set_buffered(gio, FALSE);
+ g_io_channel_set_close_on_unref(gio, TRUE);
+
+ /* Add I/O channel to the main event loop. */
+ if ( ! g_io_add_watch(gio, G_IO_IN | G_IO_HUP, (GIOFunc) lxterminal_socket_accept_client, lxtermwin))
+ {
+ g_warning("Cannot add watch on GIOChannel\n");
+ close(fd);
+ g_io_channel_unref(gio);
+ return TRUE;
+ }
+
+ /* Channel will automatically shut down when the watch returns FALSE. */
+ g_io_channel_set_close_on_unref(gio, TRUE);
+ g_io_channel_unref(gio);
+ return TRUE;
+ }
+ else
+ {
+ g_free(socket_path);
+
+ /* Create a glib I/O channel. */
+ GIOChannel * gio = g_io_channel_unix_new(fd);
+ g_io_channel_set_encoding(gio, NULL, NULL);
+
+ /* Reissue arguments to the socket. Start with the name of the executable. */
+ g_io_channel_write_chars(gio, arguments->executable, -1, NULL, NULL);
+
+ /* --command or -e. */
+ if (arguments->command != NULL)
+ {
+ gchar * command = g_shell_quote(arguments->command);
+ gchar * command_argument = g_strdup_printf(" --command=%s", command);
+ g_io_channel_write_chars(gio, command_argument, -1, NULL, NULL);
+ g_free(command);
+ g_free(command_argument);
+ }
+
+ /* --geometry. */
+ if ((arguments->geometry_columns != 0) && (arguments->geometry_rows != 0))
+ {
+ gchar * geometry = g_strdup_printf(" --geometry=%dx%d", arguments->geometry_columns, arguments->geometry_rows);
+ g_io_channel_write_chars(gio, geometry, -1, NULL, NULL);
+ g_free(geometry);
+ }
+
+ /* -t, -T, or --title. */
+ if (arguments->title != NULL)
+ {
+ gchar * title = g_shell_quote(arguments->title);
+ gchar * title_argument = g_strdup_printf(" --title=%s", title);
+ g_io_channel_write_chars(gio, title_argument, -1, NULL, NULL);
+ g_free(title);
+ g_free(title_argument);
+ }
+
+ /* Always issue a --working-directory, either from the user's specification or the current directory. */
+ gchar * working_directory = ((arguments->working_directory != NULL) ? g_shell_quote(arguments->working_directory) : g_get_current_dir());
+ gchar * working_directory_argument = g_strdup_printf(" --working-directory=%s", working_directory);
+ g_io_channel_write_chars(gio, working_directory_argument, -1, NULL, NULL);
+ g_free(working_directory);
+ g_free(working_directory_argument);
+
+ /* Finish up the transaction on the Unix domain socket. */
+ g_io_channel_write_chars(gio, "\n", -1, NULL, NULL);
+ g_io_channel_flush(gio, NULL);
+ g_io_channel_unref(gio);
+ return FALSE;
+ }
}
diff --git a/src/unixsocket.h b/src/unixsocket.h
index ac32e3f..db8f73c 100644
--- a/src/unixsocket.h
+++ b/src/unixsocket.h
@@ -1,7 +1,27 @@
+/**
+ * Copyright 2008 Fred Chien <cfsghost@gmail.com>
+ * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
#ifndef LXTERMINAL_UNIXSOCKET_H
#define LXTERMINAL_UNIXSOCKET_H
-gboolean lxterminal_socket_init(LXTermWindow *lxtermwin, int argc, char **argv);
+extern gboolean lxterminal_socket_initialize(LXTermWindow * lxtermwin, CommandArguments * arguments);
#endif
--
1.7.0.1