Remmina - The GTK+ Remote Desktop Client  v1.4.2
Remmina is a remote desktop client written in GTK+, aiming to be useful for system administrators and travellers, who need to work with lots of remote computers in front of either large monitors or tiny netbooks. Remmina supports multiple network protocols in an integrated and consistent user interface. Currently RDP, VNC, NX, XDMCP and SSH are supported.
remmina_log.c
Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2010 Vic Lee
4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
5  * Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  * In addition, as a special exception, the copyright holders give
23  * permission to link the code of portions of this program with the
24  * OpenSSL library under certain conditions as described in each
25  * individual source file, and distribute linked combinations
26  * including the two.
27  * You must obey the GNU General Public License in all respects
28  * for all of the code used other than OpenSSL. * If you modify
29  * file(s) with this exception, you may extend this exception to your
30  * version of the file(s), but you are not obligated to do so. * If you
31  * do not wish to do so, delete this exception statement from your
32  * version. * If you delete this exception statement from all source
33  * files in the program, then also delete it here.
34  *
35  */
36 
37 #include <gtk/gtk.h>
38 #include <glib/gi18n.h>
39 #include "remmina_public.h"
40 #include "remmina_log.h"
41 #include "remmina_stats_sender.h"
43 
44 /***** Define the log window GUI *****/
45 #define REMMINA_TYPE_LOG_WINDOW (remmina_log_window_get_type())
46 #define REMMINA_LOG_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), REMMINA_TYPE_LOG_WINDOW, RemminaLogWindow))
47 #define REMMINA_LOG_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), REMMINA_TYPE_LOG_WINDOW, RemminaLogWindowClass))
48 #define REMMINA_IS_LOG_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), REMMINA_TYPE_LOG_WINDOW))
49 #define REMMINA_IS_LOG_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), REMMINA_TYPE_LOG_WINDOW))
50 #define REMMINA_LOG_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), REMMINA_TYPE_LOG_WINDOW, RemminaLogWindowClass))
51 
52 typedef struct _RemminaLogWindow {
53  GtkWindow window;
54 
55  GtkWidget *log_view;
56  GtkTextBuffer *log_buffer;
58 
59 typedef struct _RemminaLogWindowClass {
60  GtkWindowClass parent_class;
62 
64 G_GNUC_CONST;
65 
66 G_DEFINE_TYPE(RemminaLogWindow, remmina_log_window, GTK_TYPE_WINDOW)
67 
68 static void remmina_log_window_class_init(RemminaLogWindowClass *klass)
69 {
70  TRACE_CALL(__func__);
71 }
72 
73 /* We will always only have one log window per instance */
74 static GtkWidget *log_window = NULL;
75 
76 static gboolean remmina_log_on_keypress(GtkWidget *widget, GdkEvent *event, gpointer user_data)
77 {
78  TRACE_CALL(__func__);
79  GdkEventKey *e = (GdkEventKey *)event;
80 
81  if (!log_window)
82  return FALSE;
83 
84  if ((e->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK) {
85  if ((e->keyval == GDK_KEY_s || e->keyval == GDK_KEY_t) && remmina_stat_sender_can_send()) {
86  remmina_stats_sender_send(e->keyval != GDK_KEY_s);
87  }
88  return TRUE;
89  }
90 
91  return FALSE;
92 }
93 
95 {
96  TRACE_CALL(__func__);
97  GtkWidget *scrolledwindow;
98  GtkWidget *widget;
99 
100  gtk_container_set_border_width(GTK_CONTAINER(logwin), 4);
101 
102  scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
103  gtk_widget_show(scrolledwindow);
104  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
105  gtk_container_add(GTK_CONTAINER(logwin), scrolledwindow);
106 
107  widget = gtk_text_view_new();
108  gtk_widget_show(widget);
109  gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(widget), GTK_WRAP_WORD_CHAR);
110  gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), FALSE);
111  gtk_container_add(GTK_CONTAINER(scrolledwindow), widget);
112  logwin->log_view = widget;
113  logwin->log_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
114 
115  g_signal_connect(G_OBJECT(logwin->log_view), "key-press-event", G_CALLBACK(remmina_log_on_keypress), (gpointer)logwin);
116 }
117 
118 static GtkWidget*
120 {
121  TRACE_CALL(__func__);
122  return GTK_WIDGET(g_object_new(REMMINA_TYPE_LOG_WINDOW, NULL));
123 }
124 
125 static void remmina_log_end(GtkWidget *widget, gpointer data)
126 {
127  TRACE_CALL(__func__);
128  log_window = NULL;
129 }
130 
132 {
133  TRACE_CALL(__func__);
134  if (log_window) {
135  gtk_window_present(GTK_WINDOW(log_window));
136  }else {
138  gtk_window_set_default_size(GTK_WINDOW(log_window), 640, 480);
139  g_signal_connect(G_OBJECT(log_window), "destroy", G_CALLBACK(remmina_log_end), NULL);
140  gtk_widget_show(log_window);
141  }
143  remmina_log_print("Shortcut keys for stats:\n"
144  "\tCTRL+S: collect, show and send stats\n"
145  "\tCTRL+T: collect and show stats\n");
146 }
147 
148 gboolean remmina_log_running(void)
149 {
150  TRACE_CALL(__func__);
151  return (log_window != NULL);
152 }
153 
154 static gboolean remmina_log_scroll_to_end(gpointer data)
155 {
156  TRACE_CALL(__func__);
157  GtkTextIter iter;
158 
159  if (log_window) {
160  gtk_text_buffer_get_end_iter(REMMINA_LOG_WINDOW(log_window)->log_buffer, &iter);
161  gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(REMMINA_LOG_WINDOW(log_window)->log_view), &iter, 0.0, FALSE, 0.0,
162  0.0);
163  }
164  return FALSE;
165 }
166 
167 static gboolean remmina_log_print_real(gpointer data)
168 {
169  TRACE_CALL(__func__);
170  GtkTextIter iter;
171 
172  if (log_window) {
173  gtk_text_buffer_get_end_iter(REMMINA_LOG_WINDOW(log_window)->log_buffer, &iter);
174  gtk_text_buffer_insert(REMMINA_LOG_WINDOW(log_window)->log_buffer, &iter, (const gchar*)data, -1);
175  IDLE_ADD(remmina_log_scroll_to_end, NULL);
176  }
177  g_free(data);
178  return FALSE;
179 }
180 
181 void remmina_log_print(const gchar *text)
182 {
183  TRACE_CALL(__func__);
184  if (!log_window)
185  return;
186 
187  IDLE_ADD(remmina_log_print_real, g_strdup(text));
188 }
189 
194 void remmina_debug(const gchar *fmt, ...)
195 {
196  /* IMPORTANT: DO NOT USE TRACES IN THIS FUNCION */
197  /* DO NOT USE TRACE_CALL(__func__); */
198 
199  va_list args;
200  gchar *text;
201  va_start(args, fmt);
202  text = g_strdup_vprintf(fmt, args);
203  va_end(args);
204  g_autofree gchar *buf = g_strconcat("(", fun, ") - ", text, NULL);
205 
206  g_debug ("%s", g_strdup(buf));
207 
208  buf = g_strconcat (buf, "\n", NULL);
209 
210  if (!log_window)
211  return;
212  IDLE_ADD(remmina_log_print_real, g_strdup(buf));
213 }
214 
215 void remmina_log_printf(const gchar *fmt, ...)
216 {
217  TRACE_CALL(__func__);
218  va_list args;
219  gchar *text;
220 
221  if (!log_window) return;
222 
223  va_start(args, fmt);
224  text = g_strdup_vprintf(fmt, args);
225  va_end(args);
226 
227  IDLE_ADD(remmina_log_print_real, text);
228 }
229 
void remmina_log_start(void)
Definition: remmina_log.c:131
GtkWindow window
Definition: remmina_log.c:53
static gboolean remmina_log_print_real(gpointer data)
Definition: remmina_log.c:167
struct _RemminaLogWindowClass RemminaLogWindowClass
static gboolean remmina_log_scroll_to_end(gpointer data)
Definition: remmina_log.c:154
GtkTextBuffer * log_buffer
Definition: remmina_log.c:56
gboolean remmina_log_running(void)
Definition: remmina_log.c:148
GtkWidget * log_view
Definition: remmina_log.c:55
void remmina_debug(const gchar *fmt,...)
Print a string in the Remmina Debug Windows and in the terminal.
Definition: remmina_log.c:194
G_DEFINE_TYPE(RemminaConnectionWindow, rcw, GTK_TYPE_WINDOW)
Definition: rcw.c:75
static void remmina_log_window_init(RemminaLogWindow *logwin)
Definition: remmina_log.c:94
char * fun
Definition: remmina_main.c:69
static gboolean remmina_log_on_keypress(GtkWidget *widget, GdkEvent *event, gpointer user_data)
Definition: remmina_log.c:76
GType remmina_log_window_get_type(void)
Definition: remmina_log.c:63
static GtkWidget * remmina_log_window_new(void)
Definition: remmina_log.c:119
struct _RemminaLogWindow RemminaLogWindow
static GtkWidget * log_window
Definition: remmina_log.c:74
void remmina_log_printf(const gchar *fmt,...)
Definition: remmina_log.c:215
gboolean remmina_stat_sender_can_send()
void remmina_stats_sender_send(gboolean show_only)
void remmina_log_print(const gchar *text)
Definition: remmina_log.c:181
static void remmina_log_end(GtkWidget *widget, gpointer data)
Definition: remmina_log.c:125
GtkWindowClass parent_class
Definition: remmina_log.c:60