summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/menu_gtk.h
blob: ee0114ef8ab419bb11c5ee2372eae62862bcc9d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_GTK_MENU_GTK_H_
#define CHROME_BROWSER_GTK_MENU_GTK_H_
#pragma once

#include <gtk/gtk.h>

#include <string>
#include <vector>

#include "base/task.h"
#include "gfx/point.h"

class SkBitmap;

namespace menus {
class ButtonMenuItemModel;
class MenuModel;
}

class MenuGtk {
 public:
  // Delegate class that lets another class control the status of the menu.
  class Delegate {
   public:
    virtual ~Delegate() { }

    // Called before a command is executed. This exists for the case where a
    // model is handling the actual execution of commands, but the delegate
    // still needs to know that some command got executed. This is called before
    // and not after the command is executed because its execution may delete
    // the menu and/or the delegate.
    virtual void CommandWillBeExecuted() {}

    // Called when the menu stops showing. This will be called before
    // ExecuteCommand if the user clicks an item, but will also be called when
    // the user clicks away from the menu.
    virtual void StoppedShowing() {}

    // Return true if we should override the "gtk-menu-images" system setting
    // when showing image menu items for this menu.
    virtual bool AlwaysShowImages() const { return false; }

    // Returns a tinted image used in button in a menu.
    virtual GtkIconSet* GetIconSetForId(int idr) { return NULL; }
  };

  MenuGtk(MenuGtk::Delegate* delegate, menus::MenuModel* model);
  ~MenuGtk();

  // Initialize GTK signal handlers.
  void ConnectSignalHandlers();

  // These methods are used to build the menu dynamically. The return value
  // is the new menu item.
  GtkWidget* AppendMenuItemWithLabel(int command_id, const std::string& label);
  GtkWidget* AppendMenuItemWithIcon(int command_id, const std::string& label,
                                    const SkBitmap& icon);
  GtkWidget* AppendCheckMenuItemWithLabel(int command_id,
                                          const std::string& label);
  GtkWidget* AppendSeparator();
  GtkWidget* AppendMenuItem(int command_id, GtkWidget* menu_item);
  GtkWidget* AppendMenuItemToMenu(int command_id,
                                  GtkWidget* menu_item,
                                  GtkWidget* menu,
                                  bool connect_to_activate);

  // Displays the menu. |timestamp| is the time of activation. The popup is
  // statically positioned at |widget|.
  void Popup(GtkWidget* widget, gint button_type, guint32 timestamp);

  // Displays the menu using the button type and timestamp of |event|. The popup
  // is statically positioned at |widget|.
  void Popup(GtkWidget* widget, GdkEvent* event);

  // Displays the menu as a context menu, i.e. at the current cursor location.
  // |event_time| is the time of the event that triggered the menu's display.
  void PopupAsContext(guint32 event_time);

  // Displays the menu at the given coords. |point| is intentionally not const.
  void PopupAsContextAt(guint32 event_time, gfx::Point point);

  // Displays the menu following a keyboard event (such as selecting |widget|
  // and pressing "enter").
  void PopupAsFromKeyEvent(GtkWidget* widget);

  // Closes the menu.
  void Cancel();

  // Repositions the menu to be right under the button.  Alignment is set as
  // object data on |void_widget| with the tag "left_align".  If "left_align"
  // is true, it aligns the left side of the menu with the left side of the
  // button. Otherwise it aligns the right side of the menu with the right side
  // of the button. Public since some menus have odd requirements that don't
  // belong in a public class.
  static void WidgetMenuPositionFunc(GtkMenu* menu,
                                     int* x,
                                     int* y,
                                     gboolean* push_in,
                                     void* void_widget);

  // Positions the menu to appear at the gfx::Point represented by |userdata|.
  static void PointMenuPositionFunc(GtkMenu* menu,
                                    int* x,
                                    int* y,
                                    gboolean* push_in,
                                    gpointer userdata);

  GtkWidget* widget() const { return menu_; }

 private:
  // Builds a GtkImageMenuItem.
  GtkWidget* BuildMenuItemWithImage(const std::string& label,
                                    const SkBitmap& icon);

  // A function that creates a GtkMenu from |model_|.
  void BuildMenuFromModel();
  // Implementation of the above; called recursively.
  void BuildSubmenuFromModel(menus::MenuModel* model, GtkWidget* menu);
  // Builds a menu item with buttons in it from the data in the model.
  GtkWidget* BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
                                 GtkWidget* menu);

  // Contains implementation for OnMenuShow.
  void UpdateMenu();

  void ExecuteCommand(menus::MenuModel* model, int id);

  // Callback for when a menu item is clicked.
  static void OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu);

  // Called when one of the buttons are pressed.
  static void OnMenuButtonPressed(GtkMenuItem* menuitem, int command_id,
                                  MenuGtk* menu);

  // Sets the check mark and enabled/disabled state on our menu items.
  static void SetMenuItemInfo(GtkWidget* widget, void* raw_menu);

  // Updates all the menu items' state.
  static void OnMenuShow(GtkWidget* widget, MenuGtk* menu);

  // Sets the activating widget back to a normal appearance.
  static void OnMenuHidden(GtkWidget* widget, MenuGtk* menu);

  // Queries this object about the menu state.
  MenuGtk::Delegate* delegate_;

  // If non-NULL, the MenuModel that we use to populate and control the GTK
  // menu (overriding the delegate as a controller).
  menus::MenuModel* model_;

  // For some menu items, we want to show the accelerator, but not actually
  // explicitly handle it. To this end we connect those menu items' accelerators
  // to this group, but don't attach this group to any top level window.
  GtkAccelGroup* dummy_accel_group_;

  // gtk_menu_popup() does not appear to take ownership of popup menus, so
  // MenuGtk explicitly manages the lifetime of the menu.
  GtkWidget* menu_;

  // True when we should ignore "activate" signals.  Used to prevent
  // menu items from getting activated when we are setting up the
  // menu.
  static bool block_activation_;

  // We must free these at shutdown.
  std::vector<MenuGtk*> submenus_we_own_;

  ScopedRunnableMethodFactory<MenuGtk> factory_;
};

#endif  // CHROME_BROWSER_GTK_MENU_GTK_H_