From 40e8a50c6b4423692d943b6572ea5b1726b1790a Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Sat, 14 Aug 2004 23:44:05 +0000 Subject: [PATCH] First working version git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1532 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/tray-monitor/TODO | 2 + bacula/src/tray-monitor/eggstatusicon.c | 9 + bacula/src/tray-monitor/eggstatusicon.h | 3 + bacula/src/tray-monitor/tray-monitor.c | 273 ++++++++++++++++++------ 4 files changed, 217 insertions(+), 70 deletions(-) create mode 100644 bacula/src/tray-monitor/TODO diff --git a/bacula/src/tray-monitor/TODO b/bacula/src/tray-monitor/TODO new file mode 100644 index 0000000000..94ceac041a --- /dev/null +++ b/bacula/src/tray-monitor/TODO @@ -0,0 +1,2 @@ + +- Check if GtkTextBuffer is freed when GtkTextView use another one. \ No newline at end of file diff --git a/bacula/src/tray-monitor/eggstatusicon.c b/bacula/src/tray-monitor/eggstatusicon.c index 7b4ce61e7a..dab162b1ee 100644 --- a/bacula/src/tray-monitor/eggstatusicon.c +++ b/bacula/src/tray-monitor/eggstatusicon.c @@ -19,6 +19,7 @@ * * Authors: * Mark McLoughlin + * Nicolas Boichat (add access to the underlying EggTrayIcon) */ #include @@ -777,3 +778,11 @@ egg_status_icon_get_is_blinking (EggStatusIcon *status_icon) return status_icon->priv->blinking; } + +EggTrayIcon* +egg_status_icon_get_tray_icon (EggStatusIcon *status_icon) +{ + g_return_val_if_fail (EGG_IS_STATUS_ICON (status_icon), NULL); + + return EGG_TRAY_ICON(status_icon->priv->tray_icon); +} diff --git a/bacula/src/tray-monitor/eggstatusicon.h b/bacula/src/tray-monitor/eggstatusicon.h index cde7ae9df0..59411556e3 100644 --- a/bacula/src/tray-monitor/eggstatusicon.h +++ b/bacula/src/tray-monitor/eggstatusicon.h @@ -19,6 +19,7 @@ * * Authors: * Mark McLoughlin + * Nicolas Boichat (add access to the underlying EggTrayIcon) */ #ifndef __EGG_STATUS_ICON_H__ @@ -96,6 +97,8 @@ void egg_status_icon_set_is_blinking (EggStatusIcon *st gboolean enable_blinking); gboolean egg_status_icon_get_is_blinking (EggStatusIcon *status_icon); +EggTrayIcon* egg_status_icon_get_tray_icon (EggStatusIcon *status_icon); + G_END_DECLS #endif /* __EGG_STATUS_ICON_H__ */ diff --git a/bacula/src/tray-monitor/tray-monitor.c b/bacula/src/tray-monitor/tray-monitor.c index e06e8ebbb8..ffdcbe3ea2 100644 --- a/bacula/src/tray-monitor/tray-monitor.c +++ b/bacula/src/tray-monitor/tray-monitor.c @@ -43,7 +43,6 @@ int authenticate_file_daemon(JCR *jcr, MONITOR *monitor, CLIENT* client); /* Forward referenced functions */ -static void terminate_console(int sig); void writecmd(const char* command); /* Static variables */ @@ -51,11 +50,34 @@ static char *configfile = NULL; static BSOCK *FD_sock = NULL; static MONITOR *monitor; static POOLMEM *args; +static JCR jcr; +static CLIENT* filed; /* UI variables and functions */ -gboolean fd_read(gpointer data); - +enum stateenum { + error, + idle, + running, + saving, + warn +}; + +stateenum currentstatus = warn; + +static gboolean fd_read(gpointer data); +void trayMessage(const char *fmt,...); +void changeIcon(stateenum status); +void writeToTextBuffer(GtkTextBuffer *buffer, const char *fmt,...); + +/* Callbacks */ +static void TrayIconActivate(GtkWidget *widget, gpointer data); +static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data); + +static gint timerTag; static EggStatusIcon* mTrayIcon; +GtkWidget *window; +GtkWidget *textview; +GtkTextBuffer *buffer; #define CONFIG_FILE "./tray-monitor.conf" /* default configuration file */ @@ -82,8 +104,6 @@ int main(int argc, char *argv[]) { int ch, nfiled; bool test_config = false; - JCR jcr; - CLIENT* filed; init_stack_dump(); my_name_is(argc, argv, "tray-monitor"); @@ -144,121 +164,234 @@ Without that I don't how to get status from the Client :-(\n"), configfile); } if (test_config) { - terminate_console(0); exit(0); } - LockRes(); - filed = (CLIENT*)GetNextRes(R_CLIENT, NULL); - UnlockRes(); - - memset(&jcr, 0, sizeof(jcr)); - (void)WSA_Init(); /* Initialize Windows sockets */ - - printf(_("Connecting to Client %s:%d\n"), filed->address, filed->FDport); - FD_sock = bnet_connect(NULL, 5, 15, "File daemon", filed->address, - NULL, filed->FDport, 0); - if (FD_sock == NULL) { - terminate_console(0); - return 1; - } - jcr.file_bsock = FD_sock; - + LockRes(); monitor = (MONITOR*)GetNextRes(R_MONITOR, (RES *)NULL); UnlockRes(); - if (!authenticate_file_daemon(&jcr, monitor, filed)) { - fprintf(stderr, "ERR=%s", FD_sock->msg); - terminate_console(0); - return 1; - } - - printf("Opened connection with File daemon\n"); - - writecmd("status"); - gtk_init (&argc, &argv); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_xpm_data(xpm_idle); + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_xpm_data(xpm_warn); // This should be ideally replaced by a completely libpr0n-based icon rendering. mTrayIcon = egg_status_icon_new_from_pixbuf(pixbuf); -/* g_signal_connect(G_OBJECT(mTrayIcon), "activate", G_CALLBACK(TrayIconActivate), this); - g_signal_connect(G_OBJECT(mTrayIcon), "popup-menu", G_CALLBACK(TrayIconPopupMenu), this);*/ + g_signal_connect(G_OBJECT(mTrayIcon), "activate", G_CALLBACK(TrayIconActivate), NULL); +/* g_signal_connect(G_OBJECT(mTrayIcon), "popup-menu", G_CALLBACK(TrayIconPopupMenu), this);*/ g_object_unref(G_OBJECT(pixbuf)); - gtk_idle_add( fd_read, NULL ); + timerTag = g_timeout_add( 5000, fd_read, NULL ); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_window_set_title(GTK_WINDOW(window), "Bacula tray monitor"); + + g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL); + //g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); + + gtk_container_set_border_width(GTK_CONTAINER(window), 10); - gtk_main(); + textview = gtk_text_view_new(); + + buffer = gtk_text_buffer_new(NULL); + + gtk_text_buffer_set_text(buffer, "", -1); + + PangoFontDescription *font_desc = pango_font_description_from_string ("Fixed 10"); + gtk_widget_modify_font(textview, font_desc); + pango_font_description_free (font_desc); + gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), FALSE); + + gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer); + + gtk_container_add(GTK_CONTAINER (window), textview); + + gtk_widget_show(textview); + + fd_read(NULL); + + gtk_main(); + if (FD_sock) { + writecmd("status"); bnet_sig(FD_sock, BNET_TERMINATE); /* send EOF */ bnet_close(FD_sock); } - terminate_console(0); + free_pool_memory(args); + (void)WSACleanup(); /* Cleanup Windows sockets */ return 0; } -gboolean fd_read(gpointer data) { +static gboolean delete_event( GtkWidget *widget, + GdkEvent *event, + gpointer data ) { + gtk_widget_hide(window); + return TRUE; /* do not destroy the window */ +} + +static void TrayIconActivate(GtkWidget *widget, gpointer data) { + gtk_widget_show(window); +} + +static gboolean fd_read(gpointer data) { int stat; + int statuschanged = 0; + GtkTextBuffer *newbuffer = gtk_text_buffer_new(NULL); + GtkTextIter start, stop, nstart, nstop; + + gtk_text_buffer_set_text (newbuffer, "", -1); + + if (!FD_sock) { + LockRes(); + filed = (CLIENT*)GetNextRes(R_CLIENT, NULL); + UnlockRes(); + + memset(&jcr, 0, sizeof(jcr)); + + writeToTextBuffer(newbuffer, "Connecting to Client %s:%d\n", filed->address, filed->FDport); + FD_sock = bnet_connect(NULL, 3, 3, "File daemon", filed->address, + NULL, filed->FDport, 0); + if (FD_sock == NULL) { + changeIcon(error); + return 1; + } + jcr.file_bsock = FD_sock; + + if (!authenticate_file_daemon(&jcr, monitor, filed)) { + writeToTextBuffer(newbuffer, "ERR=%s", FD_sock->msg); + FD_sock = NULL; + changeIcon(error); + return 0; + } + + trayMessage("Opened connection with File daemon"); + } + + writecmd("status"); while(1) { if ((stat = bnet_recv(FD_sock)) >= 0) { - printf(FD_sock->msg); + writeToTextBuffer(newbuffer, FD_sock->msg); + if (strstr(FD_sock->msg, " is running.") != NULL) { + changeIcon(running); + statuschanged = 1; + } + else if (strstr(FD_sock->msg, "No Jobs running.") != NULL) { + changeIcon(idle); + statuschanged = 1; + } } else if (stat == BNET_SIGNAL) { - if (FD_sock->msglen == BNET_PROMPT) { - printf(""); - } - else if (FD_sock->msglen == BNET_EOD) { - printf(""); - writecmd("status"); - sleep(1); - return 1; + if (FD_sock->msglen == BNET_EOD) { + if (statuschanged == 0) { + changeIcon(warn); + } + break; } else if (FD_sock->msglen == BNET_HEARTBEAT) { bnet_sig(FD_sock, BNET_HB_RESPONSE); - printf("<< Heartbeat signal received, answered. >>"); + writeToTextBuffer(newbuffer, "<< Heartbeat signal received, answered. >>"); } else { - printf("<< Unexpected signal received : %s >>", bnet_sig_to_ascii(FD_sock)); + writeToTextBuffer(newbuffer, "<< Unexpected signal received : %s >>", bnet_sig_to_ascii(FD_sock)); } } else { /* BNET_HARDEOF || BNET_ERROR */ - printf(""); + writeToTextBuffer(newbuffer, "\n"); + FD_sock = NULL; + changeIcon(error); break; } if (is_bnet_stop(FD_sock)) { - printf(""); + writeToTextBuffer(newbuffer, "\n"); + FD_sock = NULL; + changeIcon(error); break; /* error or term */ } } - return 0; + + /* Keep the selection if necessary */ + if (gtk_text_buffer_get_selection_bounds(buffer, &start, &stop)) { + gtk_text_buffer_get_iter_at_offset(newbuffer, &nstart, gtk_text_iter_get_offset(&start)); + gtk_text_buffer_get_iter_at_offset(newbuffer, &nstop, gtk_text_iter_get_offset(&stop )); + gtk_text_buffer_select_range(newbuffer, &nstart, &nstop); + } + + buffer = newbuffer; + gtk_text_view_set_buffer(GTK_TEXT_VIEW(textview), buffer); + + return 1; } -/* Cleanup and then exit */ -static void terminate_console(int sig) -{ +void writecmd(const char* command) { + if (FD_sock) { + FD_sock->msglen = strlen(command); + pm_strcpy(&FD_sock->msg, command); + bnet_send(FD_sock); + } +} - static bool already_here = false; +/* Note: Does not seem to work either on Gnome nor KDE... */ +void trayMessage(const char *fmt,...) { + char buf[3000]; + va_list arg_ptr; + + va_start(arg_ptr, fmt); + bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr); + va_end(arg_ptr); + + egg_tray_icon_send_message(egg_status_icon_get_tray_icon(mTrayIcon), 5000, (const char*)&buf, -1); +} - if (already_here) { /* avoid recursive temination problems */ - exit(1); - } - already_here = true; - free_pool_memory(args); - (void)WSACleanup(); /* Cleanup Windows sockets */ - if (sig != 0) { - exit(1); +void changeIcon(stateenum status) { + if (status == currentstatus) + return; + + const char** xpm; + + switch (status) { + case error: + xpm = (const char**)&xpm_error; + break; + case idle: + xpm = (const char**)&xpm_idle; + break; + case running: + xpm = (const char**)&xpm_running; + break; + case saving: + xpm = (const char**)&xpm_saving; + break; + case warn: + xpm = (const char**)&xpm_warn; + break; + default: + xpm = NULL; + break; } - return; + + GdkPixbuf* pixbuf = gdk_pixbuf_new_from_xpm_data(xpm); + // This should be ideally replaced by a completely libpr0n-based icon rendering. + egg_status_icon_set_from_pixbuf(mTrayIcon, pixbuf); + + currentstatus = status; } -void writecmd(const char* command) { - FD_sock->msglen = strlen(command); - pm_strcpy(&FD_sock->msg, command); - bnet_send(FD_sock); +void writeToTextBuffer(GtkTextBuffer *buffer, const char *fmt,...) { + char buf[3000]; + va_list arg_ptr; + GtkTextIter iter; + + va_start(arg_ptr, fmt); + bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr); + va_end(arg_ptr); + + gtk_text_buffer_get_end_iter(buffer, &iter); + gtk_text_buffer_insert(buffer, &iter, buf, -1); } + -- 2.39.5