8 #include <yui/Libyui_config.h>
9 #include "ygtkmenubutton.h"
11 #include <gdk/gdkkeysyms.h>
20 GtkWindow *window = GTK_WINDOW (popup);
21 gtk_window_set_resizable (window, FALSE);
23 GtkWidget *frame = gtk_frame_new (NULL);
24 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
25 gtk_widget_show (frame);
26 gtk_container_add (GTK_CONTAINER (window), frame);
29 static void ygtk_popup_window_hide (GtkWidget *widget)
31 gtk_grab_remove (widget);
32 GTK_WIDGET_CLASS (ygtk_popup_window_parent_class)->hide (widget);
35 static gboolean ygtk_popup_window_key_press_event (GtkWidget *widget, GdkEventKey *event)
37 if (event->keyval == GDK_KEY_Escape) {
38 gtk_widget_hide (widget);
41 return GTK_WIDGET_CLASS (ygtk_popup_window_parent_class)->key_press_event
45 static gboolean ygtk_popup_window_button_press_event (GtkWidget *widget,
46 GdkEventButton *event)
53 GtkWidget *child = gtk_get_event_widget ((GdkEvent *) event);
58 child = gtk_widget_get_parent(child);
60 gtk_widget_hide (widget);
64 GtkWidget *ygtk_popup_window_new (GtkWidget *child)
66 GtkWidget *widget = g_object_new (YGTK_TYPE_POPUP_WINDOW,
67 "type", GTK_WINDOW_POPUP, NULL);
68 GtkWidget *frame = gtk_bin_get_child (GTK_BIN (widget));
69 gtk_container_add (GTK_CONTAINER (frame), child);
73 static void ygtk_popup_window_frame_position (GtkWidget *widget, gint *x, gint *y)
76 gtk_widget_get_preferred_size(widget, &req, NULL);
78 GdkScreen *screen = gtk_widget_get_screen (widget);
81 # if GTK_CHECK_VERSION (3, 22, 0)
82 GdkMonitor *monitor_num = gdk_display_get_monitor_at_window (
83 gdk_screen_get_display (screen),
84 gdk_screen_get_root_window (screen));
85 gdk_monitor_get_geometry (monitor_num, &monitor);
86 # elif GTK_CHECK_VERSION (3, 12, 0)
87 gint monitor_num = gdk_screen_get_monitor_at_window (screen,
88 gdk_screen_get_root_window (screen));
89 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
91 gint monitor_num = gdk_screen_get_monitor_at_window (screen,
92 gtk_widget_get_root_window (widget));
93 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
98 else if (*x + req.width > monitor.x + monitor.width)
99 *x = monitor.x + monitor.width - req.width;
103 else if (*y + req.height > monitor.y + monitor.height)
104 *y = monitor.y + monitor.height - req.height;
107 void ygtk_popup_window_popup (GtkWidget *widget, gint x, gint y, guint activate_time)
109 ygtk_popup_window_frame_position (widget, &x, &y);
111 gtk_grab_add (widget);
112 gtk_window_move (GTK_WINDOW (widget), x, y);
113 gtk_widget_grab_focus (widget);
114 gtk_widget_show (widget);
116 GdkWindow *window = gtk_widget_get_window (widget);
118 GdkDisplay *display = gdk_window_get_display (window);
120 # if GTK_CHECK_VERSION (3, 20, 0)
121 GdkSeat *seat = gdk_display_get_default_seat (display);
122 GdkDevice *pointer = gdk_seat_get_pointer (seat);
124 GdkDeviceManager *device_manager = gdk_display_get_device_manager (display);
125 GdkDevice *pointer = gdk_device_manager_get_client_pointer (device_manager);
129 if (gdk_device_grab (pointer, window, GDK_OWNERSHIP_NONE, TRUE,
130 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK,
131 NULL, activate_time) == 0) {
133 keyboard = gdk_device_get_associated_device (pointer);
134 if (gdk_device_grab (keyboard, window, GDK_OWNERSHIP_NONE, TRUE,
135 GDK_KEY_PRESS | GDK_KEY_RELEASE, NULL, activate_time) != 0)
136 gdk_device_ungrab (pointer, activate_time);
142 ygtk_popup_window_parent_class = g_type_class_peek_parent (klass);
144 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
145 widget_class->key_press_event = ygtk_popup_window_key_press_event;
146 widget_class->button_press_event = ygtk_popup_window_button_press_event;
147 widget_class->hide = ygtk_popup_window_hide;
152 G_DEFINE_TYPE (
YGtkMenuButton, ygtk_menu_button, GTK_TYPE_TOGGLE_BUTTON)
161 gtk_widget_destroy (GTK_WIDGET (button->popup));
162 g_object_unref (G_OBJECT (button->popup));
163 button->popup = NULL;
167 static void ygtk_menu_button_finalize (GObject *
object)
169 ygtk_menu_button_free_popup (YGTK_MENU_BUTTON (
object));
170 G_OBJECT_CLASS (ygtk_menu_button_parent_class)->finalize (
object);
173 static void ygtk_menu_button_get_popup_pos (
YGtkMenuButton *button, gint *x, gint *y)
175 GtkWidget *widget = GTK_WIDGET (button);
176 GtkAllocation button_alloc;
177 gtk_widget_get_allocation(widget, &button_alloc);
181 gtk_widget_get_preferred_size (button->popup, &req, NULL);
182 int popup_width = req.width, popup_height = req.height;
183 if (button_alloc.width > req.width) {
184 gtk_widget_set_size_request (button->popup, button_alloc.width, -1);
185 popup_width = button_alloc.width;
188 gdk_window_get_origin (gtk_widget_get_window(widget), x, y);
189 *x += button_alloc.x - popup_width*button->xalign;
190 *y += (button_alloc.y-popup_height) + (button_alloc.height+popup_height)*button->yalign;
193 # if GTK_CHECK_VERSION (3, 22, 0)
194 GdkScreen *screen = gtk_widget_get_screen (widget);
195 GdkRectangle monitor;
197 GdkMonitor *monitor_num = gdk_display_get_monitor_at_window (
198 gdk_screen_get_display (screen),
199 gdk_screen_get_root_window (screen));
200 gdk_monitor_get_geometry (monitor_num, &monitor);
202 int screen_height = monitor.y;
204 int screen_height = gdk_screen_get_height (gtk_widget_get_screen (widget));
207 if (*y > screen_height - popup_height)
208 *y -= popup_height + button_alloc.height;
211 #if GTK_CHECK_VERSION (3, 22, 0)
213 static void ygtk_menu_button_get_menu_pos (GtkMenu *menu, gint *x, gint *y,
214 gboolean *push_in, gpointer data)
216 ygtk_menu_button_get_popup_pos (YGTK_MENU_BUTTON (data), x, y);
223 GtkWidget *popup = button->popup;
227 guint activate_time = gtk_get_current_event_time();
228 if (GTK_IS_MENU (popup))
230 # if GTK_CHECK_VERSION (3, 22, 0)
231 gtk_menu_popup_at_pointer (GTK_MENU (popup), NULL);
233 gtk_menu_popup (GTK_MENU (popup), NULL, NULL,
234 ygtk_menu_button_get_menu_pos,
235 button, 0, activate_time);
240 ygtk_menu_button_get_popup_pos (button, &x, &y);
241 ygtk_popup_window_popup (popup, x, y, activate_time);
247 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
250 static void ygtk_menu_button_button_toggle (GtkToggleButton *button)
252 if (gtk_toggle_button_get_active (button))
253 ygtk_menu_button_show_popup (YGTK_MENU_BUTTON (button));
255 ygtk_menu_button_hide_popup (YGTK_MENU_BUTTON (button));
258 static gint ygtk_menu_button_button_press (GtkWidget *widget, GdkEventButton *event)
260 if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
261 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
262 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
263 ygtk_menu_button_show_popup (YGTK_MENU_BUTTON (widget));
266 ygtk_menu_button_hide_popup (YGTK_MENU_BUTTON (widget));
272 GtkWidget *ygtk_menu_button_new (
void)
274 return g_object_new (YGTK_TYPE_MENU_BUTTON, NULL);
277 GtkWidget *ygtk_menu_button_new_with_label (
const gchar *label)
279 GtkWidget *button = ygtk_menu_button_new();
280 ygtk_menu_button_set_label (YGTK_MENU_BUTTON (button), label);
284 void ygtk_menu_button_set_label (
YGtkMenuButton *button,
const gchar *label)
286 if (!button->label) {
287 GtkWidget *hbox, *arrow;
288 hbox = YGTK_HBOX_NEW(4);
289 gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
291 # if GTK_CHECK_VERSION (3, 14, 0)
292 arrow = gtk_image_new_from_icon_name (
"pan-down-symbolic",
293 GTK_ICON_SIZE_BUTTON);
295 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
298 button->label = gtk_label_new (
"");
299 gtk_box_pack_start (GTK_BOX (hbox), button->label, TRUE, TRUE, 0);
300 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, TRUE, 0);
301 gtk_container_add (GTK_CONTAINER (button), hbox);
302 gtk_widget_show_all (hbox);
304 if (label && *label) {
305 gtk_widget_show (button->label);
306 gtk_label_set_text_with_mnemonic (GTK_LABEL (button->label), label);
309 gtk_widget_hide (button->label);
312 static void menu_button_hide_popup (GtkWidget *widget,
YGtkMenuButton *button)
313 { ygtk_menu_button_hide_popup (button); }
315 void ygtk_menu_button_set_popup_align (
YGtkMenuButton *button, GtkWidget *popup,
316 gfloat xalign, gfloat yalign)
318 ygtk_menu_button_free_popup (button);
319 button->xalign = xalign;
320 button->yalign = yalign;
322 if (!GTK_IS_MENU (popup) && !IS_YGTK_POPUP_WINDOW (popup)) {
324 button->popup = ygtk_popup_window_new (popup);
327 button->popup = popup;
329 g_object_ref_sink (G_OBJECT (button->popup));
330 g_signal_connect (G_OBJECT (button->popup),
"hide",
331 G_CALLBACK (menu_button_hide_popup), button);
334 void ygtk_menu_button_set_popup (
YGtkMenuButton *button, GtkWidget *popup)
336 ygtk_menu_button_set_popup_align (button, popup, 0.0, 1.0);
341 ygtk_menu_button_parent_class = g_type_class_peek_parent (klass);
343 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
344 gobject_class->finalize = ygtk_menu_button_finalize;
346 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
347 widget_class->button_press_event = ygtk_menu_button_button_press;
349 GtkToggleButtonClass *toggle_button_class = GTK_TOGGLE_BUTTON_CLASS (klass);
350 toggle_button_class->toggled = ygtk_menu_button_button_toggle;