summaryrefslogtreecommitdiffstats
path: root/webkit/plugins/npapi/gtk_plugin_container_manager.cc
blob: d018714b7f3e9dd08d40e365d43d8ab69ff8f4f4 (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
// Copyright (c) 2012 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 "webkit/plugins/npapi/gtk_plugin_container_manager.h"

#include <gtk/gtk.h>

#include "base/logging.h"
#include "ui/base/gtk/gtk_compat.h"
#include "ui/gfx/gtk_util.h"
#include "webkit/plugins/npapi/gtk_plugin_container.h"
#include "webkit/plugins/npapi/webplugin.h"

namespace webkit {
namespace npapi {

GtkPluginContainerManager::GtkPluginContainerManager() : host_widget_(NULL) {}

GtkPluginContainerManager::~GtkPluginContainerManager() {}

GtkWidget* GtkPluginContainerManager::CreatePluginContainer(
    gfx::PluginWindowHandle id) {
  DCHECK(host_widget_);
  GtkWidget *widget = gtk_plugin_container_new();
  plugin_window_to_widget_map_.insert(std::make_pair(id, widget));

  // The Realize callback is responsible for adding the plug into the socket.
  // The reason is 2-fold:
  // - the plug can't be added until the socket is realized, but this may not
  // happen until the socket is attached to a top-level window, which isn't the
  // case for background tabs.
  // - when dragging tabs, the socket gets unrealized, which breaks the XEMBED
  // connection. We need to make it again when the tab is reattached, and the
  // socket gets realized again.
  //
  // Note, the RealizeCallback relies on the plugin_window_to_widget_map_ to
  // have the mapping.
  g_signal_connect(widget, "realize",
                   G_CALLBACK(RealizeCallback), this);

  // Don't destroy the widget when the plug is removed.
  g_signal_connect(widget, "plug-removed",
                   G_CALLBACK(gtk_true), NULL);

  gtk_container_add(GTK_CONTAINER(host_widget_), widget);
  gtk_widget_show(widget);

  return widget;
}

void GtkPluginContainerManager::DestroyPluginContainer(
    gfx::PluginWindowHandle id) {
  DCHECK(host_widget_);
  GtkWidget* widget = MapIDToWidget(id);
  if (widget)
    gtk_widget_destroy(widget);

  plugin_window_to_widget_map_.erase(id);
}

void GtkPluginContainerManager::MovePluginContainer(
    const WebPluginGeometry& move) {
  DCHECK(host_widget_);
  GtkWidget *widget = MapIDToWidget(move.window);
  if (!widget)
    return;

  DCHECK(gtk_widget_get_has_window(widget));

  if (!move.visible) {
    gtk_widget_hide(widget);
    return;
  }

  gtk_widget_show(widget);

  if (!move.rects_valid)
    return;

  // TODO(piman): if the widget hasn't been realized (e.g. the tab has been
  // torn off and the parent gtk widget has been detached from the hierarchy),
  // we lose the cutout information.
  if (gtk_widget_get_realized(widget)) {
    GdkRectangle clip_rect = move.clip_rect.ToGdkRectangle();
    GdkRegion* clip_region = gdk_region_rectangle(&clip_rect);
    gfx::SubtractRectanglesFromRegion(clip_region, move.cutout_rects);
    gdk_window_shape_combine_region(gtk_widget_get_window(widget),
                                    clip_region, 0, 0);
    gdk_region_destroy(clip_region);
  }

  // Update the window position.  Resizing is handled by WebPluginDelegate.
  // TODO(deanm): Verify that we only need to move and not resize.
  // TODO(evanm): we should cache the last shape and position and skip all
  // of this business in the common case where nothing has changed.
  int current_x, current_y;

  // Until the above TODO is resolved, we can grab the last position
  // off of the GtkFixed with a bit of hackery.
  GValue value = {0};
  g_value_init(&value, G_TYPE_INT);
  gtk_container_child_get_property(GTK_CONTAINER(host_widget_), widget,
                                   "x", &value);
  current_x = g_value_get_int(&value);
  gtk_container_child_get_property(GTK_CONTAINER(host_widget_), widget,
                                   "y", &value);
  current_y = g_value_get_int(&value);
  g_value_unset(&value);

  if (move.window_rect.x() != current_x ||
      move.window_rect.y() != current_y) {
    // Calling gtk_fixed_move unnecessarily is a no-no, as it causes the
    // parent window to repaint!
    gtk_fixed_move(GTK_FIXED(host_widget_),
                   widget,
                   move.window_rect.x(),
                   move.window_rect.y());
  }

  gtk_plugin_container_set_size(widget,
                                move.window_rect.width(),
                                move.window_rect.height());
}

GtkWidget* GtkPluginContainerManager::MapIDToWidget(
    gfx::PluginWindowHandle id) {
  PluginWindowToWidgetMap::const_iterator i =
      plugin_window_to_widget_map_.find(id);
  if (i != plugin_window_to_widget_map_.end())
    return i->second;

  LOG(ERROR) << "Request for widget host for unknown window id " << id;

  return NULL;
}

gfx::PluginWindowHandle GtkPluginContainerManager::MapWidgetToID(
     GtkWidget* widget) {
  for (PluginWindowToWidgetMap::const_iterator i =
          plugin_window_to_widget_map_.begin();
       i != plugin_window_to_widget_map_.end(); ++i) {
    if (i->second == widget)
      return i->first;
  }

  LOG(ERROR) << "Request for id for unknown widget";
  return 0;
}

// static
void GtkPluginContainerManager::RealizeCallback(GtkWidget* widget,
                                                void* user_data) {
  GtkPluginContainerManager* plugin_container_manager =
      static_cast<GtkPluginContainerManager*>(user_data);

  gfx::PluginWindowHandle id = plugin_container_manager->MapWidgetToID(widget);
  if (id)
    gtk_socket_add_id(GTK_SOCKET(widget), id);
}

}  // namespace npapi
}  // namespace webkit