diff --git a/gnoemoe/widgets/gm-app-view.c b/gnoemoe/widgets/gm-app-view.c index c05b670..9625e94 100644 --- a/gnoemoe/widgets/gm-app-view.c +++ b/gnoemoe/widgets/gm-app-view.c @@ -29,6 +29,7 @@ #include "mcp/gm-mcp-session.h" #include "mcp/gm-mcp-package.h" #include "gm-searchable.h" +#include "gm-tray.h" //#include "if_world.h" //#include "if_worlds_listing.h" @@ -41,10 +42,6 @@ //#include "world.h" //#include "net.h" //#include "main.h" - -void on_gm_app_view_destroy(GtkWidget * caller, gpointer user_data); -gboolean on_gm_app_view_focus_in(GtkWidget *widget, GdkEventFocus *event, - gpointer user_data); void on_gm_app_view_entry_find_activate(GtkEntry *entry, GmAppView *view); void on_gm_app_view_entry_find_changed(GtkEditable *editable, @@ -70,6 +67,10 @@ gboolean on_gm_app_view_notebook_button_release(GtkNotebook *notebook, void on_gm_app_view_check_button_search_direction_toggled( GtkToggleButton *button, GmAppView *view); +gboolean on_gm_app_view_tray_button_press(GmTray *tray, GdkEventButton *event, + GmAppView *view); +void on_gm_app_view_tray_destroy(GtkWidget *caller, GmAppView *view); + void on_gm_app_view_world_mcp_package_created(GmMcpSession *session, GmMcpPackage *package, GmAppView *view); @@ -92,15 +93,21 @@ void on_gm_app_view_world_activate(GtkAction * action, GmWorld *world); void on_gm_app_view_world_load(GmWorld *world, GmAppView *view); void on_gm_app_view_world_unload(GmWorld *world, GmAppView *view); void on_gm_app_view_world_activate_request(GmWorld *world, GmAppView *view); -void on_gm_app_view_world_name_changed(GmWorld *world, const gchar *name, +void on_gm_app_view_world_name_changed(GmWorld *world, GParamSpec *pspec, + GmAppView *view); +void on_gm_app_view_world_active_changed(GmWorld *world, GParamSpec *pspec, + GmAppView *view); +void on_gm_app_view_world_activity_changed(GmWorld *world, GParamSpec *pspec, GmAppView *view); void on_gm_app_view_world_state_changing(GmWorld *world, GmNetState state, GmAppView *view); -void on_gm_app_view_world_active_changed(GmWorld *world, gboolean active, +void on_gm_app_view_world_notify_message(GmWorld *world, gchar const *message, GmAppView *view); void on_gm_app_view_world_view_destroy(GmWorldView *world_view, GmAppView *view); +GmWorld *gm_app_view_active_world(GmAppView *view); + #define GM_APP_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \ GM_TYPE_APP_VIEW, GmAppViewPrivate)) @@ -119,6 +126,7 @@ struct _GmAppViewPrivate { GtkActionGroup *action_group; GtkActionGroup *worlds_action_group; GHashTable *world_menu_items; + GmTray *tray; GtkNotebook *notebook; GmWorld *active_world; @@ -158,19 +166,84 @@ gm_app_view_finalize(GObject *object) { gm_scripts_dialog_fini(); - if (view->priv->cursor) + if (view->priv->cursor) { gdk_cursor_unref(view->priv->cursor); + } + + //if (view->priv->tray) { + // gtk_widget_destroy(GTK_WIDGET(view->priv->tray)); + //} g_hash_table_destroy(view->priv->world_menu_items); G_OBJECT_CLASS(gm_app_view_parent_class)->finalize(object); } +static void +gm_app_view_destroy(GtkObject *object) { + if (GTK_OBJECT_CLASS(gm_app_view_parent_class)->destroy) { + GTK_OBJECT_CLASS(gm_app_view_parent_class)->destroy(object); + } + + gtk_main_quit(); +} + +static gboolean +gm_app_view_focus_in_event(GtkWidget *widget, GdkEventFocus *event) { + GmAppView *view = GM_APP_VIEW(widget); + GmWorld *world; + + world = gm_app_view_active_world(view); + + if (world) { + gm_world_set_active(world, TRUE); + } + + if (view->priv->tray) { + gm_tray_normal(view->priv->tray); + } + + gtk_window_set_urgency_hint(GTK_WINDOW(view), FALSE); + + if (GTK_WIDGET_CLASS(gm_app_view_parent_class)->focus_in_event) { + return GTK_WIDGET_CLASS(gm_app_view_parent_class)->focus_in_event( + widget, event); + } + + return FALSE; +} + +static gboolean +gm_app_view_focus_out_event(GtkWidget *widget, GdkEventFocus *event) { + GmAppView *view = GM_APP_VIEW(widget); + GmWorld *world; + + world = gm_app_view_active_world(view); + + if (world) { + // Set the world to inactive so activity is counted and tray will + // update properly + gm_world_set_active(world, FALSE); + } + + if (GTK_WIDGET_CLASS(gm_app_view_parent_class)->focus_out_event) { + return GTK_WIDGET_CLASS(gm_app_view_parent_class)->focus_out_event( + widget, event); + } + + return FALSE; + } static void gm_app_view_class_init(GmAppViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); - + GtkObjectClass *gobject_class = GTK_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + object_class->finalize = gm_app_view_finalize; + gobject_class->destroy = gm_app_view_destroy; + + widget_class->focus_in_event = gm_app_view_focus_in_event; + widget_class->focus_out_event = gm_app_view_focus_out_event; g_type_class_add_private(object_class, sizeof(GmAppViewPrivate)); } @@ -441,10 +514,6 @@ gm_app_view_init(GmAppView *view) { gtk_window_set_title(GTK_WINDOW(view), "GnoeMoe"); gtk_window_set_icon(GTK_WINDOW(view), gm_pixbuf_get("gnoemoe_logo.svg")); - - g_signal_connect(view, "destroy", G_CALLBACK(on_gm_app_view_destroy), NULL); - g_signal_connect(view, "focus_in_event", - G_CALLBACK(on_gm_app_view_focus_in), NULL); /* Signals for tab reordering */ g_signal_connect_after(note, "switch-page", @@ -465,6 +534,26 @@ gm_app_view_init(GmAppView *view) { view->priv->cursor = NULL; gm_scripts_dialog_init(); + + if (gm_tray_has_manager()) { + view->priv->tray = gm_tray_new(_("GnoeMoe Gnome MOO Client")); + + gm_tray_set_icon(view->priv->tray, TRAY_STATE_NORMAL, + gm_pixbuf_get("tray/default.svg")); + gm_tray_set_icon(view->priv->tray, TRAY_STATE_ACTIVE, + gm_pixbuf_get("tray/active.svg")); + gm_tray_set_icon(view->priv->tray, TRAY_STATE_NOTIFY, + gm_pixbuf_get("tray/notify.svg")); + gm_tray_set_icon(view->priv->tray, TRAY_STATE_ACTIVITY, + gm_pixbuf_get("tray/activity.svg")); + + gtk_widget_show(GTK_WIDGET(view->priv->tray)); + + g_signal_connect(view->priv->tray, "button-press-event", + G_CALLBACK(on_gm_app_view_tray_button_press), view); + g_signal_connect(view->priv->tray, "destroy", + G_CALLBACK(on_gm_app_view_tray_destroy), view); + } } @@ -621,136 +710,80 @@ gm_app_view_worlds_loaded(GmAppView *view) { "/MenuBar/EditMenu/EditReplaceMenu"), FALSE); } -/* TODO: move to custom widget thingie, and put control in gm-app instead - of gm-app-view -static gboolean -have_tray(void) { - Screen *xscreen = DefaultScreenOfDisplay(gdk_display); - Atom selection_atom; - char *selection_atom_name; +void +gm_app_view_update_tray(GmAppView *view) { + GList *worlds; + GmWorld *world; + gchar *tmp; + gboolean active = gtk_window_is_active(GTK_WINDOW(view)); + gint activity; + GString *str = NULL; - selection_atom_name = g_strdup_printf("_NET_SYSTEM_TRAY_S%d", - XScreenNumberOfScreen(xscreen)); - selection_atom = XInternAtom(DisplayOfScreen(xscreen), - selection_atom_name, False); - g_free(selection_atom_name); - - if (XGetSelectionOwner(DisplayOfScreen(xscreen), selection_atom)) { - return TRUE; + if (!view->priv->tray) { + return; + } + + if (!active) { + for (worlds = gm_app_worlds(gm_app_instance()); worlds; + worlds = worlds->next) { + world = GM_WORLD(worlds->data); + activity = gm_world_activity(world); + + if (gm_world_loaded(world) && activity) { + if (!str) { + tmp = g_strdup_printf(_("Activity in:\n%s (%d)"), + gm_world_name(world), activity); + str = g_string_new(NULL); + } else { + tmp = g_strdup_printf(", %s (%d)", + gm_world_name(world), activity); + } + + str = g_string_append(str, tmp); + g_free(tmp); + } + } + + if (str) { + gm_tray_activate(view->priv->tray); + } else if (gm_tray_get_state(view->priv->tray) != TRAY_STATE_NOTIFY) { + gm_tray_normal(view->priv->tray); + } + + if (gm_tray_get_state(view->priv->tray) != TRAY_STATE_NOTIFY) { + if (str) { + gm_tray_set_tip(view->priv->tray, str->str); + } else { + gm_tray_set_tip(view->priv->tray, NULL); + } + } + + if (str) { + g_string_free(str, TRUE); + } } else { - return FALSE; + gm_tray_normal(view->priv->tray); } } -static gboolean -tray_flash_restore_func(gpointer data) { - switch (app_tray_info.iconnr) { - case TRAY_ICON_ACTIVE: - gtk_image_set_from_pixbuf(GTK_IMAGE(app_tray_info.image), - gnoe_pixbuf_get("tray/active.svg")); - break; - case TRAY_ICON_DEFAULT: - gtk_image_set_from_pixbuf(GTK_IMAGE(app_tray_info.image), - gnoe_pixbuf_get("tray/default.svg")); - break; - case TRAY_ICON_NOTIFY: - gtk_image_set_from_pixbuf(GTK_IMAGE(app_tray_info.image), - gnoe_pixbuf_get("tray/notify.svg")); - break; - } - - app_tray_info.flash_timeout = -1; - return FALSE; -} - void -tray_activate() { - if (app_tray_info.flash_timeout != 0) { - g_source_remove(app_tray_info.flash_timeout); - } - - gtk_image_set_from_pixbuf(GTK_IMAGE(app_tray_info.image), - gnoe_pixbuf_get("tray/activate.svg")); - app_tray_info.flash_timeout = g_timeout_add(1000, tray_flash_restore_func, NULL); +gm_app_view_toggle_visibility(GmAppView *view) { + gboolean visible = GTK_WIDGET_VISIBLE(view); + + if (!visible || !gtk_window_is_active(GTK_WINDOW(view))) { + gtk_widget_show(GTK_WIDGET(view)); + gtk_window_present(GTK_WINDOW(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); + + if (view->priv->tray) { + gm_tray_normal(view->priv->tray); + } + } else if (view->priv->tray) { + gtk_widget_hide(GTK_WIDGET(view)); + } } -void -tray_set_notify(gchar *text) { - gboolean active = gtk_window_is_active(GTK_WINDOW(wndMain)); - - if (!active) { - app_tray_info.iconnr = TRAY_ICON_NOTIFY; - tray_flash_restore_func(NULL); - - egg_tray_icon_send_message(app_tray_info.icon, 2000, text, g_utf8_strlen(text, -1)); - gtk_tooltips_set_tip(app_tray_info.tooltips, app_tray_info.event_box, text, text); - } -} - -void -tray_update() { - GList *wlds; - world *wld; - gchar *tmp = NULL, *tmp2 = NULL; - gboolean active = gtk_window_is_active(GTK_WINDOW(wndMain)); - - if (!active) { - for (wlds = world_get_worlds(); wlds; wlds = wlds->next) { - wld = (world *)(wlds->data); - if (wld->loaded && wld->inactive > 0) { - if (tmp == NULL) { - tmp = g_strdup_printf(_("Activity in:\n%s (%d)"), options_get_str( - wld->settings, "name"), wld->inactive); - } else { - tmp2 = g_strdup_printf("%s, %s (%d)", tmp, options_get_str( - wld->settings, "name"), wld->inactive); - g_free(tmp); - tmp = g_strdup(tmp2); - g_free(tmp2); - tmp2 = NULL; - } - } - } - - if (tmp) { - app_tray_info.iconnr = TRAY_ICON_ACTIVE; - tray_activate(); - } else if (app_tray_info.iconnr != TRAY_ICON_NOTIFY) { - app_tray_info.iconnr = TRAY_ICON_DEFAULT; - tray_flash_restore_func(NULL); - } - - if (app_tray_info.iconnr != TRAY_ICON_NOTIFY) { - gtk_tooltips_set_tip(app_tray_info.tooltips, app_tray_info.event_box, tmp, tmp); - } - - g_free(tmp); - } else { - app_tray_info.iconnr = TRAY_ICON_DEFAULT; - tray_flash_restore_func(NULL); - gtk_tooltips_set_tip(app_tray_info.tooltips, app_tray_info.event_box, NULL, NULL); - } -} - -void -if_main_show_hide(gboolean show) { - world *wld; - - if (show || !gtk_window_is_active(GTK_WINDOW(wndMain))) { - gtk_widget_show(wndMain); - gtk_window_present(GTK_WINDOW(wndMain)); - wld = world_get_active(); - - if (wld) { - wld->inactive = 0; - } - - tray_update(); - } else { - gtk_widget_hide(wndMain); - } -}*/ - GmWorldView * gm_app_view_world_view_from_world(GmAppView *view, GmWorld *world) { GtkNotebook *book = view->priv->notebook; @@ -769,11 +802,6 @@ gm_app_view_world_view_from_world(GmAppView *view, GmWorld *world) { /* Callbacks */ -void -on_gm_app_view_destroy(GtkWidget * caller, gpointer user_data) { - gtk_main_quit(); -} - void on_gm_app_view_world_close(GtkMenuItem * menuitem, GmAppView *view) { GmWorld *world = gm_app_view_active_world(view); @@ -789,11 +817,11 @@ on_gm_app_view_world_close_from_tab(GmWorldTab *tab, GmWorld *world) { } void -on_gm_app_view_world_name_changed(GmWorld *world, const gchar *name, +on_gm_app_view_world_name_changed(GmWorld *world, GParamSpec *pspec, GmAppView *view) { GmAppViewWorldMenuItem *item = (GmAppViewWorldMenuItem *) g_hash_table_lookup(view->priv->world_menu_items, world); - g_object_set(G_OBJECT(item->action), "label", name, NULL); + g_object_set(G_OBJECT(item->action), "label", gm_world_name(world), NULL); if (world == gm_app_view_active_world(view)) { gm_app_view_update_title(view); @@ -842,13 +870,17 @@ on_gm_app_view_world_added(GmApp *app, GmWorld *world, GmAppView *view) { G_CALLBACK(on_gm_app_view_world_unload), view); g_signal_connect(world, "activate_request", G_CALLBACK(on_gm_app_view_world_activate_request), view); - g_signal_connect(world, "name_changed", + g_signal_connect(world, "notify::name", G_CALLBACK(on_gm_app_view_world_name_changed), view); g_signal_connect(world, "state_changing", G_CALLBACK(on_gm_app_view_world_state_changing), view); - g_signal_connect(world, "active_changed", + g_signal_connect(world, "notify::active", G_CALLBACK(on_gm_app_view_world_active_changed), view); - + g_signal_connect(world, "notify::activity", + G_CALLBACK(on_gm_app_view_world_activity_changed), view); + g_signal_connect(world, "notify_message", + G_CALLBACK(on_gm_app_view_world_notify_message), view); + g_hash_table_insert(view->priv->world_menu_items, world, item); g_free(name); g_free(tooltip); @@ -922,6 +954,18 @@ on_gm_app_view_world_activate_request(GmWorld *world, GmAppView *view) { gm_world_set_active(world, TRUE); } +void +on_gm_app_view_world_notify_message(GmWorld *world, gchar const *message, + GmAppView *view) { + if (!gtk_window_is_active(GTK_WINDOW(view))) { + if (view->priv->tray) { + gm_tray_notify(view->priv->tray, message); + } + + gtk_window_set_urgency_hint(GTK_WINDOW(view), TRUE); + } +} + void on_gm_app_view_world_quit(GtkMenuItem *menuitem, GmAppView *view) { gtk_widget_destroy(GTK_WIDGET(view)); @@ -1602,11 +1646,11 @@ on_gm_app_view_world_logs(GtkMenuItem *menuitem, GmAppView *view) { } void -on_gm_app_view_world_active_changed(GmWorld *world, gboolean active, +on_gm_app_view_world_active_changed(GmWorld *world, GParamSpec *pspec, GmAppView *view) { GmWorldView *world_view = gm_app_view_world_view_from_world(view, world); - if (active) { + if (gm_world_active(world)) { gtk_notebook_set_current_page(view->priv->notebook, gtk_notebook_page_num(view->priv->notebook, GTK_WIDGET(world_view))); @@ -1614,22 +1658,10 @@ on_gm_app_view_world_active_changed(GmWorld *world, gboolean active, } } -gboolean -on_gm_app_view_focus_in(GtkWidget *widget, GdkEventFocus *event, - gpointer user_data) { - /* TODO: implementation - world *wld; - - wld = world_get_active(); - - if (wld) { - world_activated(wld); - } - - app_tray_info.iconnr = TRAY_ICON_DEFAULT; - tray_flash_restore_func(NULL);*/ - - return FALSE; +void +on_gm_app_view_world_activity_changed(GmWorld *world, GParamSpec *pspec, + GmAppView *view) { + gm_app_view_update_tray(view); } void @@ -1653,3 +1685,24 @@ on_gm_app_view_world_view_destroy(GmWorldView *world_view, gm_world_unload(world); } } + +gboolean +on_gm_app_view_tray_button_press(GmTray *tray, GdkEventButton *event, + GmAppView *view) { + if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { + return FALSE; + } + + if (event->button == 1) { + gm_app_view_toggle_visibility(view); + } + + return FALSE; +} + +void +on_gm_app_view_tray_destroy(GtkWidget *caller, GmAppView *view) { + // Make sure the view is visible + view->priv->tray = NULL; + gtk_widget_show(GTK_WIDGET(view)); +}