Add ShellMenu
An object with methods and signals useful for implementing popup menus.
This commit is contained in:
parent
42bf91fdc4
commit
22c445cffc
@ -75,6 +75,8 @@ libgnome_shell_la_SOURCES = \
|
|||||||
shell-generic-container.h \
|
shell-generic-container.h \
|
||||||
shell-gtk-embed.c \
|
shell-gtk-embed.c \
|
||||||
shell-gtk-embed.h \
|
shell-gtk-embed.h \
|
||||||
|
shell-menu.c \
|
||||||
|
shell-menu.h \
|
||||||
shell-overflow-list.c \
|
shell-overflow-list.c \
|
||||||
shell-overflow-list.h \
|
shell-overflow-list.h \
|
||||||
shell-process.c \
|
shell-process.c \
|
||||||
|
243
src/shell-menu.c
Normal file
243
src/shell-menu.c
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:shell-menu
|
||||||
|
* @short_description: A box which acts like a popup menu
|
||||||
|
*
|
||||||
|
* A #BigBox subclass which adds methods and signals useful for implementing
|
||||||
|
* popup-menu like actors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "shell-menu.h"
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(ShellMenu, shell_menu, BIG_TYPE_BOX);
|
||||||
|
|
||||||
|
struct _ShellMenuPrivate {
|
||||||
|
gboolean have_grab;
|
||||||
|
|
||||||
|
ClutterActor *selected;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Signals */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
UNSELECTED,
|
||||||
|
SELECTED,
|
||||||
|
ACTIVATE,
|
||||||
|
POPDOWN,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint shell_menu_signals [LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
shell_menu_contains (ShellMenu *box,
|
||||||
|
ClutterActor *actor)
|
||||||
|
{
|
||||||
|
while (actor != NULL && actor != (ClutterActor*)box)
|
||||||
|
{
|
||||||
|
actor = clutter_actor_get_parent (actor);
|
||||||
|
}
|
||||||
|
return actor != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_selected_destroy (ClutterActor *actor,
|
||||||
|
ShellMenu *box)
|
||||||
|
{
|
||||||
|
box->priv->selected = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_selected (ShellMenu *box,
|
||||||
|
ClutterActor *actor)
|
||||||
|
{
|
||||||
|
if (actor == box->priv->selected)
|
||||||
|
return;
|
||||||
|
if (box->priv->selected)
|
||||||
|
{
|
||||||
|
g_signal_handlers_disconnect_by_func (box->priv->selected, G_CALLBACK(on_selected_destroy), box);
|
||||||
|
g_signal_emit (G_OBJECT (box), shell_menu_signals[UNSELECTED], 0, box->priv->selected);
|
||||||
|
}
|
||||||
|
box->priv->selected = actor;
|
||||||
|
if (box->priv->selected)
|
||||||
|
{
|
||||||
|
g_signal_connect (box->priv->selected, "destroy", G_CALLBACK(on_selected_destroy), box);
|
||||||
|
g_signal_emit (G_OBJECT (box), shell_menu_signals[SELECTED], 0, box->priv->selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
shell_menu_enter_event (ClutterActor *actor,
|
||||||
|
ClutterCrossingEvent *event)
|
||||||
|
{
|
||||||
|
ShellMenu *box = SHELL_MENU (actor);
|
||||||
|
|
||||||
|
if (!shell_menu_contains (box, event->source))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (event->source == (ClutterActor*)box)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (g_object_get_data (G_OBJECT (event->source), "shell-is-separator"))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
set_selected (box, event->source);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
shell_menu_leave_event (ClutterActor *actor,
|
||||||
|
ClutterCrossingEvent *event)
|
||||||
|
{
|
||||||
|
ShellMenu *box = SHELL_MENU (actor);
|
||||||
|
|
||||||
|
set_selected (box, NULL);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
shell_menu_button_release_event (ClutterActor *actor,
|
||||||
|
ClutterButtonEvent *event)
|
||||||
|
{
|
||||||
|
ShellMenu *box = SHELL_MENU (actor);
|
||||||
|
|
||||||
|
if (event->button != 1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
shell_menu_popdown (box);
|
||||||
|
|
||||||
|
if (!shell_menu_contains (box, event->source))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (box->priv->selected == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
g_signal_emit (G_OBJECT (box), shell_menu_signals[ACTIVATE], 0, box->priv->selected);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
shell_menu_popup (ShellMenu *box,
|
||||||
|
guint button,
|
||||||
|
guint32 activate_time)
|
||||||
|
{
|
||||||
|
box->priv->have_grab = TRUE;
|
||||||
|
clutter_grab_pointer (CLUTTER_ACTOR (box));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
shell_menu_popdown (ShellMenu *box)
|
||||||
|
{
|
||||||
|
if (box->priv->have_grab)
|
||||||
|
clutter_ungrab_pointer ();
|
||||||
|
clutter_actor_hide (CLUTTER_ACTOR (box));
|
||||||
|
g_signal_emit (G_OBJECT (box), shell_menu_signals[POPDOWN], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shell_menu_append_separator:
|
||||||
|
* @box:
|
||||||
|
* @separator: An actor which functions as a menu separator
|
||||||
|
* @flags: Packing flags
|
||||||
|
*
|
||||||
|
* Actors added to the menu with default functions are treated like
|
||||||
|
* menu items; this function will add an actor that should instead
|
||||||
|
* be treated like a menu separator. The current practical effect
|
||||||
|
* is that the separators will not be selectable.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
shell_menu_append_separator (ShellMenu *box,
|
||||||
|
ClutterActor *separator,
|
||||||
|
BigBoxPackFlags flags)
|
||||||
|
{
|
||||||
|
g_object_set_data (G_OBJECT (separator), "shell-is-separator", GUINT_TO_POINTER(TRUE));
|
||||||
|
big_box_append (BIG_BOX (box), separator, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shell_menu_class_init (ShellMenuClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||||
|
|
||||||
|
actor_class->enter_event = shell_menu_enter_event;
|
||||||
|
actor_class->leave_event = shell_menu_leave_event;
|
||||||
|
actor_class->button_release_event = shell_menu_button_release_event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShellMenu::unselected
|
||||||
|
* @box: The #ShellMenu
|
||||||
|
* @actor: The previously hovered-over menu item
|
||||||
|
*
|
||||||
|
* This signal is emitted when a menu item transitions to
|
||||||
|
* an unselected state.
|
||||||
|
*/
|
||||||
|
shell_menu_signals[UNSELECTED] =
|
||||||
|
g_signal_new ("unselected",
|
||||||
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0,
|
||||||
|
NULL, NULL,
|
||||||
|
g_cclosure_marshal_VOID__OBJECT,
|
||||||
|
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShellMenu::selected
|
||||||
|
* @box: The #ShellMenu
|
||||||
|
* @actor: The hovered-over menu item
|
||||||
|
*
|
||||||
|
* This signal is emitted when a menu item is in a selected state.
|
||||||
|
*/
|
||||||
|
shell_menu_signals[SELECTED] =
|
||||||
|
g_signal_new ("selected",
|
||||||
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0,
|
||||||
|
NULL, NULL,
|
||||||
|
g_cclosure_marshal_VOID__OBJECT,
|
||||||
|
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShellMenu::activate
|
||||||
|
* @box: The #ShellMenu
|
||||||
|
* @actor: The clicked menu item
|
||||||
|
*
|
||||||
|
* This signal is emitted when a menu item is selected.
|
||||||
|
*/
|
||||||
|
shell_menu_signals[ACTIVATE] =
|
||||||
|
g_signal_new ("activate",
|
||||||
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0,
|
||||||
|
NULL, NULL,
|
||||||
|
g_cclosure_marshal_VOID__OBJECT,
|
||||||
|
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShellMenu::popdown
|
||||||
|
* @box: The #ShellMenu
|
||||||
|
*
|
||||||
|
* This signal is emitted when the menu is removed from the display.
|
||||||
|
*/
|
||||||
|
shell_menu_signals[POPDOWN] =
|
||||||
|
g_signal_new ("popdown",
|
||||||
|
G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0,
|
||||||
|
NULL, NULL,
|
||||||
|
g_cclosure_marshal_VOID__OBJECT,
|
||||||
|
G_TYPE_NONE, 0);
|
||||||
|
|
||||||
|
g_type_class_add_private (gobject_class, sizeof (ShellMenuPrivate));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shell_menu_init (ShellMenu *self)
|
||||||
|
{
|
||||||
|
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SHELL_TYPE_MENU,
|
||||||
|
ShellMenuPrivate);
|
||||||
|
}
|
39
src/shell-menu.h
Normal file
39
src/shell-menu.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef __SHELL_MENU_H__
|
||||||
|
#define __SHELL_MENU_H__
|
||||||
|
|
||||||
|
#include <clutter/clutter.h>
|
||||||
|
#include "big/box.h"
|
||||||
|
|
||||||
|
#define SHELL_TYPE_MENU (shell_menu_get_type ())
|
||||||
|
#define SHELL_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_MENU, ShellMenu))
|
||||||
|
#define SHELL_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_MENU, ShellMenuClass))
|
||||||
|
#define SHELL_IS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_MENU))
|
||||||
|
#define SHELL_IS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_MENU))
|
||||||
|
#define SHELL_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_MENU, ShellMenuClass))
|
||||||
|
|
||||||
|
typedef struct _ShellMenu ShellMenu;
|
||||||
|
typedef struct _ShellMenuClass ShellMenuClass;
|
||||||
|
|
||||||
|
typedef struct _ShellMenuPrivate ShellMenuPrivate;
|
||||||
|
|
||||||
|
struct _ShellMenu
|
||||||
|
{
|
||||||
|
BigBox parent;
|
||||||
|
|
||||||
|
ShellMenuPrivate *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _ShellMenuClass
|
||||||
|
{
|
||||||
|
BigBoxClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType shell_menu_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
void shell_menu_popup (ShellMenu *behavior, guint button, guint32 activate_time);
|
||||||
|
|
||||||
|
void shell_menu_append_separator (ShellMenu *behavior, ClutterActor *separator, BigBoxPackFlags flags);
|
||||||
|
|
||||||
|
void shell_menu_popdown (ShellMenu *behavior);
|
||||||
|
|
||||||
|
#endif /* __SHELL_MENU_H__ */
|
Loading…
Reference in New Issue
Block a user