/* * Copyright (C) 2002 Anders Carlsson * Copyright (C) 2003-2006 Vincent Untz * Copyright (C) 2006, 2007 Christian Persch * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "system-tray/na-tray-manager.h" #ifdef PROVIDE_WATCHER_SERVICE # include "libstatus-notifier-watcher/gf-status-notifier-watcher.h" #endif #include "na-grid.h" #define NOTIFICATION_AREA_ICON "mate-panel-notification-area" static guint n_windows = 0; typedef struct { GdkScreen *screen; guint screen_num; GtkWidget *window; GtkWidget *traybox; GtkLabel *count_label; } TrayData; static void do_add (GtkWidget *child, guint *n_children) { *n_children += 1; } static void update_child_count (TrayData *data) { guint n_children = 0; char text[64]; if (!gtk_widget_get_realized (data->window)) return; gtk_container_foreach (GTK_CONTAINER (data->traybox), (GtkCallback) do_add, &n_children); g_snprintf (text, sizeof (text), "%u icons", n_children); gtk_label_set_text (data->count_label, text); } static void tray_added_cb (GtkContainer *box, GtkWidget *icon, TrayData *data) { g_print ("[Screen %u tray %p] Child %p added to tray: \"%s\"\n", data->screen_num, data->traybox, icon, "XXX"); /* na_tray_child_get_title (icon)); */ update_child_count (data); } static void tray_removed_cb (GtkContainer *box, GtkWidget *icon, TrayData *data) { g_print ("[Screen %u tray %p] Child %p removed from tray\n", data->screen_num, data->traybox, icon); update_child_count (data); } static void orientation_changed_cb (GtkComboBox *combo, TrayData *data) { GtkOrientation orientation = (GtkOrientation) gtk_combo_box_get_active (combo); g_print ("[Screen %u tray %p] Setting orientation to \"%s\"\n", data->screen_num, data->traybox, orientation == 0 ? "horizontal" : "vertical"); gtk_orientable_set_orientation (GTK_ORIENTABLE (data->traybox), orientation); } static void maybe_quit (gpointer data, GObject *zombie) { if (--n_windows == 0) { gtk_main_quit (); } } static TrayData *create_tray_on_screen (GdkScreen *screen, gboolean force); static void warning_dialog_response_cb (GtkWidget *dialog, gint response, GdkScreen *screen) { if (response == GTK_RESPONSE_YES) { create_tray_on_screen (screen, TRUE); } gtk_widget_destroy (dialog); } static void add_tray_cb (GtkWidget *button, TrayData *data) { create_tray_on_screen (data->screen, TRUE); } static TrayData * create_tray_on_screen (GdkScreen *screen, gboolean force) { GtkWidget *window, *hbox, *vbox, *button, *combo, *label; TrayData *data; n_windows++; if (!force && na_tray_manager_check_running (screen)) { GtkWidget *dialog; dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, "Override tray manager?"); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "There is already a tray manager running on screen %d.", gdk_x11_screen_get_screen_number (screen)); gtk_window_set_screen (GTK_WINDOW (dialog), screen); g_signal_connect (dialog, "response", G_CALLBACK (warning_dialog_response_cb), screen); gtk_window_present (GTK_WINDOW (dialog)); g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) maybe_quit, NULL); return NULL; } data = g_new0 (TrayData, 1); data->screen = screen; data->screen_num = gdk_x11_screen_get_screen_number (screen); data->window = window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_object_weak_ref (G_OBJECT (window), (GWeakNotify) maybe_quit, NULL); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_container_add (GTK_CONTAINER (window), vbox); button = gtk_button_new_with_mnemonic ("_Add another tray"); g_signal_connect (button, "clicked", G_CALLBACK (add_tray_cb), data); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new_with_mnemonic ("_Orientation:"); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_label_set_yalign (GTK_LABEL (label), 0.5); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); combo = gtk_combo_box_text_new (); gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "Horizontal"); gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "Vertical"); g_signal_connect (combo, "changed", G_CALLBACK (orientation_changed_cb), data); gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0); label = gtk_label_new (NULL); data->count_label = GTK_LABEL (label); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_label_set_yalign (GTK_LABEL (label), 0.5); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); data->traybox = na_grid_new (GTK_ORIENTATION_HORIZONTAL); gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (data->traybox), TRUE, TRUE, 0); g_signal_connect_after (data->traybox, "add", G_CALLBACK (tray_added_cb), data); g_signal_connect_after (data->traybox, "remove", G_CALLBACK (tray_removed_cb), data); gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0); gtk_window_set_screen (GTK_WINDOW (window), screen); gtk_window_set_default_size (GTK_WINDOW (window), -1, 200); /* gtk_window_set_resizable (GTK_WINDOW (window), FALSE); */ gtk_widget_show_all (window); update_child_count (data); return data; } static gboolean signal_handler (gpointer data G_GNUC_UNUSED) { gtk_main_quit (); return FALSE; } #ifdef PROVIDE_WATCHER_SERVICE static GfStatusNotifierWatcher * status_notifier_watcher_maybe_new (void) { GDBusProxy *proxy; GError *error = NULL; GfStatusNotifierWatcher *service = NULL; /* check if the service already exists * FIXME: is that a not-too-stupid way of doing it? bah, so long as it works. * it's for testing purposes only anyway. */ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, "org.kde.StatusNotifierWatcher", "/StatusNotifierWatcher", "org.kde.StatusNotifierWatcher", NULL, &error); if (proxy) g_object_unref (proxy); else { g_warning ("Failed to connect to org.kde.StatusNotifierWatcher (%s), starting our own.", error->message); g_clear_error (&error); service = gf_status_notifier_watcher_new (); } return service; } #endif int main (int argc, char *argv[]) { GdkDisplay *display; GdkScreen *screen; #ifdef PROVIDE_WATCHER_SERVICE GfStatusNotifierWatcher *service; #endif gtk_init (&argc, &argv); g_unix_signal_add (SIGTERM, signal_handler, NULL); g_unix_signal_add (SIGINT, signal_handler, NULL); #ifdef PROVIDE_WATCHER_SERVICE service = status_notifier_watcher_maybe_new (); #endif gtk_window_set_default_icon_name (NOTIFICATION_AREA_ICON); display = gdk_display_get_default (); screen = gdk_display_get_default_screen (display); create_tray_on_screen (screen, FALSE); gtk_main (); #ifdef PROVIDE_WATCHER_SERVICE if (service) g_object_unref (service); #endif return 0; }