summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/bookmark_bubble_gtk.cc
blob: 91b4c8df3182cc35ff03f189a2f6b046cdc52e21 (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
// Copyright (c) 2009 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.

#include "chrome/browser/gtk/bookmark_bubble_gtk.h"

#include <gtk/gtk.h>

#include "base/basictypes.h"
#include "base/logging.h"
#include "chrome/browser/gtk/info_bubble_gtk.h"

namespace {

// We basically have a singleton, since a bubble is sort of app-modal.  This
// keeps track of the currently open bubble, or NULL if none is open.
BookmarkBubbleGtk* g_bubble = NULL;

// TODO(deanm): Just a temporary state to keep track of the last entry in the
// combo box.  This makes sure we are catching the closing events right and
// saving the state.
gint g_last_active = 0;

}  // namespace

// static
void BookmarkBubbleGtk::Show(const gfx::Rect& rect,
                             Profile* profile,
                             const GURL& url,
                             bool newly_bookmarked) {
  // TODO(deanm): The Views code deals with the possibility of a bubble already
  // being open, and then it just does nothing.  I am not sure how this could
  // happen with the style of our GTK bubble since it has a grab.  I would also
  // think that closing the previous bubble and opening the new one would make
  // more sense, but I guess then you would commit the bubble's changes.
  DCHECK(!g_bubble);
  g_bubble = new BookmarkBubbleGtk(rect, profile, url, newly_bookmarked);
}

void BookmarkBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble,
                                          bool closed_by_escape) {
  // Possibly commit any bookmark changes here...
  g_last_active = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_));
}

BookmarkBubbleGtk::BookmarkBubbleGtk(const gfx::Rect& rect,
                                     Profile* profile,
                                     const GURL& url,
                                     bool newly_bookmarked)
    : profile_(profile),
      newly_bookmarked_(newly_bookmarked),
      content_(NULL),
      combo_(NULL) {
  // TODO(deanm): Implement the real bookmark bubble.  For now we just have
  // a placeholder for testing that input and focus works correctly.
  GtkWidget* content = gtk_vbox_new(FALSE, 5);
  gtk_box_pack_start(GTK_BOX(content), gtk_label_new("Hej!"), TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(content), gtk_entry_new(), TRUE, TRUE, 0);
  // Use a combo box just to make sure popup windows work in the bubble content
  // and we're not fighting with the bubble for the grab.
  combo_ = gtk_combo_box_new_text();
  gtk_combo_box_append_text(GTK_COMBO_BOX(combo_), "entry 1");
  gtk_combo_box_append_text(GTK_COMBO_BOX(combo_), "entry 2");
  gtk_combo_box_append_text(GTK_COMBO_BOX(combo_), "entry 3");
  gtk_combo_box_set_active(GTK_COMBO_BOX(combo_), g_last_active);
  gtk_box_pack_start(GTK_BOX(content), combo_, TRUE, TRUE, 0);

  g_signal_connect(content, "destroy",
                   G_CALLBACK(&HandleDestroyThunk), this);

  // TODO(deanm): In the future we might want to hang on to the returned
  // InfoBubble so that we can call Close() on it.
  if (!InfoBubbleGtk::Show(rect, content, this)) {
    NOTREACHED();
  }
}

BookmarkBubbleGtk::~BookmarkBubbleGtk() {
  DCHECK(!content_);  // |content_| should have already been destroyed.

  DCHECK(g_bubble);
  g_bubble = NULL;
}

gboolean BookmarkBubbleGtk::HandleDestroy() {
  // We are self deleting, we have a destroy signal setup to catch when we
  // destroyed (via the InfoBubble being destroyed), and delete ourself.
  content_ = NULL;  // We are being destroyed.
  delete this;
  return FALSE;  // Propagate.
}