/* Marco fixed tooltip routine */ /* * Copyright (C) 2001 Havoc Pennington * Copyright (C) 2003-2006 Vincent Untz * * 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 St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #ifndef HAVE_X11 #error file should only be compiled when HAVE_X11 is enabled #endif #include #include "fixedtip.h" /* Signals */ enum { CLICKED, LAST_SIGNAL }; static guint fixedtip_signals[LAST_SIGNAL] = { 0 }; struct _NaFixedTipPrivate { GtkWidget *parent; GtkWidget *label; GtkOrientation orientation; }; G_DEFINE_TYPE_WITH_PRIVATE (NaFixedTip, na_fixed_tip, GTK_TYPE_WINDOW) static gboolean button_press_handler (GtkWidget *fixedtip, GdkEventButton *event, gpointer data) { if (event->button == 1 && event->type == GDK_BUTTON_PRESS) g_signal_emit (fixedtip, fixedtip_signals[CLICKED], 0); return FALSE; } static gboolean na_fixed_tip_draw (GtkWidget *widget, cairo_t *cr) { GtkStyleContext *context; GtkStateFlags state; int width, height; width = gtk_widget_get_allocated_width (widget); height = gtk_widget_get_allocated_height (widget); state = gtk_widget_get_state_flags (widget); context = gtk_widget_get_style_context (widget); gtk_style_context_save (context); gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOOLTIP); gtk_style_context_set_state (context, state); cairo_save (cr); gtk_render_background (context, cr, 0., 0., (gdouble)width, (gdouble)height); cairo_restore (cr); gtk_style_context_restore (context); return FALSE; } static void na_fixed_tip_class_init (NaFixedTipClass *class) { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); widget_class->draw = na_fixed_tip_draw; fixedtip_signals[CLICKED] = g_signal_new ("clicked", G_OBJECT_CLASS_TYPE (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NaFixedTipClass, clicked), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } /* Did you already see this code? Yes, it's gtk_tooltips_ force_window() ;-) */ static void na_fixed_tip_init (NaFixedTip *fixedtip) { GtkWidget *label; fixedtip->priv = na_fixed_tip_get_instance_private (fixedtip); gtk_window_set_type_hint (GTK_WINDOW (fixedtip), GDK_WINDOW_TYPE_HINT_TOOLTIP); gtk_widget_set_app_paintable (GTK_WIDGET (fixedtip), TRUE); gtk_window_set_resizable (GTK_WINDOW (fixedtip), FALSE); gtk_widget_set_name (GTK_WIDGET (fixedtip), "gtk-tooltips"); gtk_container_set_border_width (GTK_CONTAINER (fixedtip), 4); label = gtk_label_new (NULL); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_xalign (GTK_LABEL (label), 0.5); gtk_label_set_yalign (GTK_LABEL (label), 0.5); gtk_widget_show (label); gtk_container_add (GTK_CONTAINER (fixedtip), label); fixedtip->priv->label = label; gtk_widget_add_events (GTK_WIDGET (fixedtip), GDK_BUTTON_PRESS_MASK); g_signal_connect (fixedtip, "button_press_event", G_CALLBACK (button_press_handler), NULL); fixedtip->priv->orientation = GTK_ORIENTATION_HORIZONTAL; } static void na_fixed_tip_position (NaFixedTip *fixedtip) { GdkScreen *screen; GdkWindow *parent_window; GtkRequisition req; int root_x; int root_y; int parent_width; int parent_height; int screen_width; int screen_height; screen = gtk_widget_get_screen (fixedtip->priv->parent); parent_window = gtk_widget_get_window (fixedtip->priv->parent); gtk_window_set_screen (GTK_WINDOW (fixedtip), screen); gtk_widget_get_preferred_size (GTK_WIDGET (fixedtip), &req, NULL); gdk_window_get_origin (parent_window, &root_x, &root_y); parent_width = gdk_window_get_width(parent_window); parent_height = gdk_window_get_height(parent_window); screen_width = WidthOfScreen (gdk_x11_screen_get_xscreen (screen)); screen_height = HeightOfScreen (gdk_x11_screen_get_xscreen (screen)); /* pad between panel and message window */ #define PAD 5 if (fixedtip->priv->orientation == GTK_ORIENTATION_VERTICAL) { if (root_x <= screen_width / 2) root_x += parent_width + PAD; else root_x -= req.width + PAD; } else { if (root_y <= screen_height / 2) root_y += parent_height + PAD; else root_y -= req.height + PAD; } /* Push onscreen */ if ((root_x + req.width) > screen_width) root_x = screen_width - req.width; if ((root_y + req.height) > screen_height) root_y = screen_height - req.height; gtk_window_move (GTK_WINDOW (fixedtip), root_x, root_y); } static void na_fixed_tip_parent_size_allocated (GtkWidget *parent, GtkAllocation *allocation, NaFixedTip *fixedtip) { na_fixed_tip_position (fixedtip); } static void na_fixed_tip_parent_screen_changed (GtkWidget *parent, GdkScreen *new_screen, NaFixedTip *fixedtip) { na_fixed_tip_position (fixedtip); } GtkWidget * na_fixed_tip_new (GtkWidget *parent, GtkOrientation orientation) { NaFixedTip *fixedtip; g_return_val_if_fail (parent != NULL, NULL); fixedtip = g_object_new (NA_TYPE_FIXED_TIP, "type", GTK_WINDOW_POPUP, NULL); fixedtip->priv->parent = parent; #if 0 //FIXME: would be nice to be able to get the toplevel for the tip, but this //doesn't work GtkWidget *toplevel; toplevel = gtk_widget_get_toplevel (parent); /* if (toplevel && gtk_widget_is_toplevel (toplevel) && GTK_IS_WINDOW (toplevel)) gtk_window_set_transient_for (GTK_WINDOW (fixedtip), GTK_WINDOW (toplevel)); */ #endif fixedtip->priv->orientation = orientation; //FIXME: would be nice to move the tip when the notification area moves g_signal_connect_object (parent, "size-allocate", G_CALLBACK (na_fixed_tip_parent_size_allocated), fixedtip, 0); g_signal_connect_object (parent, "screen-changed", G_CALLBACK (na_fixed_tip_parent_screen_changed), fixedtip, 0); na_fixed_tip_position (fixedtip); return GTK_WIDGET (fixedtip); } void na_fixed_tip_set_markup (GtkWidget *widget, const char *markup_text) { NaFixedTip *fixedtip; g_return_if_fail (NA_IS_FIXED_TIP (widget)); fixedtip = NA_FIXED_TIP (widget); gtk_label_set_markup (GTK_LABEL (fixedtip->priv->label), markup_text); na_fixed_tip_position (fixedtip); } void na_fixed_tip_set_orientation (GtkWidget *widget, GtkOrientation orientation) { NaFixedTip *fixedtip; g_return_if_fail (NA_IS_FIXED_TIP (widget)); fixedtip = NA_FIXED_TIP (widget); if (orientation == fixedtip->priv->orientation) return; fixedtip->priv->orientation = orientation; na_fixed_tip_position (fixedtip); }