summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authortschmelcher@google.com <tschmelcher@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-01 17:30:15 +0000
committertschmelcher@google.com <tschmelcher@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-01 17:30:15 +0000
commitf6618de512037e7f9701b03877f53868c47e01dc (patch)
treefcb95d8fb48791a22e6ff2e5ef5779ce265294ad /o3d
parent6b5a32b508a41b4b1e19d7ec1815ce4f6b2e1699 (diff)
downloadchromium_src-f6618de512037e7f9701b03877f53868c47e01dc.zip
chromium_src-f6618de512037e7f9701b03877f53868c47e01dc.tar.gz
chromium_src-f6618de512037e7f9701b03877f53868c47e01dc.tar.bz2
Implement fullscreen on Linux. No "Press Esc" message yet though. Also it's DISPLAY_MODE_DEFAULT only for now (mode switching is evil anyways ;) ). Small bit of code cleanup in renderer.h.
TESTED=entered and exited fullscreen; tested leaving with Esc, Alt+F4, click on region, and right-click on taskbare -> Close; all with both Compiz on and off, on gHardy. Review URL: http://codereview.chromium.org/258004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27732 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r--o3d/converter/cross/renderer_stub.cc20
-rw-r--r--o3d/converter/cross/renderer_stub.h7
-rw-r--r--o3d/core/cross/gl/renderer_gl.cc52
-rw-r--r--o3d/core/cross/gl/renderer_gl.h8
-rw-r--r--o3d/core/cross/renderer.h23
-rw-r--r--o3d/plugin/cross/o3d_glue.cc5
-rw-r--r--o3d/plugin/cross/o3d_glue.h20
-rw-r--r--o3d/plugin/linux/main_linux.cc187
8 files changed, 279 insertions, 43 deletions
diff --git a/o3d/converter/cross/renderer_stub.cc b/o3d/converter/cross/renderer_stub.cc
index 2801470..0f11826 100644
--- a/o3d/converter/cross/renderer_stub.cc
+++ b/o3d/converter/cross/renderer_stub.cc
@@ -183,6 +183,26 @@ void RendererStub::SetViewportInPixels(int, int, int, int, float, float) {
DCHECK(false);
}
+bool RendererStub::GoFullscreen(const DisplayWindow& display,
+ int mode_id) {
+ return false;
+}
+
+bool RendererStub::CancelFullscreen(const DisplayWindow& display,
+ int width, int height) {
+ return false;
+}
+
+bool RendererStub::fullscreen() const { return false; }
+
+void RendererStub::GetDisplayModes(std::vector<DisplayMode> *modes) {
+ modes->clear();
+}
+
+bool RendererStub::GetDisplayMode(int id, DisplayMode *mode) {
+ return false;
+}
+
void RendererStub::PlatformSpecificPresent(void) {
}
diff --git a/o3d/converter/cross/renderer_stub.h b/o3d/converter/cross/renderer_stub.h
index 3f0c413..514349d 100644
--- a/o3d/converter/cross/renderer_stub.h
+++ b/o3d/converter/cross/renderer_stub.h
@@ -71,6 +71,13 @@ class RendererStub : public Renderer {
int height,
float min_z,
float max_z);
+ virtual bool GoFullscreen(const DisplayWindow& display,
+ int mode_id);
+ virtual bool CancelFullscreen(const DisplayWindow& display,
+ int width, int height);
+ virtual bool fullscreen() const;
+ virtual void GetDisplayModes(std::vector<DisplayMode> *modes);
+ virtual bool GetDisplayMode(int id, DisplayMode *mode);
// Overridden from Renderer.
virtual const int* GetRGBAUByteNSwizzleTable();
diff --git a/o3d/core/cross/gl/renderer_gl.cc b/o3d/core/cross/gl/renderer_gl.cc
index 02a6942..0e2f683 100644
--- a/o3d/core/cross/gl/renderer_gl.cc
+++ b/o3d/core/cross/gl/renderer_gl.cc
@@ -1214,16 +1214,68 @@ void RendererGL::Resize(int width, int height) {
bool RendererGL::GoFullscreen(const DisplayWindow& display,
int mode_id) {
+#ifdef OS_LINUX
+ // This actually just switches the GLX context to the new window. The real
+ // work is in main_linux.cc.
+ const DisplayWindowLinux &display_platform =
+ static_cast<const DisplayWindowLinux&>(display);
+ display_ = display_platform.display();
+ window_ = display_platform.window();
+ if (!MakeCurrent()) {
+ return false;
+ }
+#endif
fullscreen_ = true;
return true;
}
bool RendererGL::CancelFullscreen(const DisplayWindow& display,
int width, int height) {
+#ifdef OS_LINUX
+ // This actually just switches the GLX context to the old window. The real
+ // work is in main_linux.cc.
+ const DisplayWindowLinux &display_platform =
+ static_cast<const DisplayWindowLinux&>(display);
+ display_ = display_platform.display();
+ window_ = display_platform.window();
+ if (!MakeCurrent()) {
+ return false;
+ }
+#endif
fullscreen_ = false;
return true;
}
+void RendererGL::GetDisplayModes(std::vector<DisplayMode> *modes) {
+#ifdef OS_MACOSX
+ // Mac is supposed to call a different function in plugin_mac.mm instead.
+ DLOG(FATAL) << "Not supposed to be called";
+#endif
+ // On all other platforms this is unimplemented. Linux only supports
+ // DISPLAY_MODE_DEFAULT for now.
+ modes->clear();
+}
+
+bool RendererGL::GetDisplayMode(int id, DisplayMode *mode) {
+#ifdef OS_MACOSX
+ // Mac is supposed to call a different function in plugin_mac.mm instead.
+ DLOG(FATAL) << "Not supposed to be called";
+ return false;
+#elif defined(OS_LINUX)
+ if (id == DISPLAY_MODE_DEFAULT) {
+ // Don't need to know any of this on Linux.
+ mode->Set(0, 0, 0, id);
+ return true;
+ } else {
+ // There are no other valid ids until we implement GetDisplayModes() and
+ // mode switching.
+ return false;
+ }
+#else
+ return false;
+#endif
+}
+
bool RendererGL::PlatformSpecificStartRendering() {
DLOG_FIRST_N(INFO, 10) << "RendererGL StartRendering";
MakeCurrentLazy();
diff --git a/o3d/core/cross/gl/renderer_gl.h b/o3d/core/cross/gl/renderer_gl.h
index 722e29e2..de2a8cb 100644
--- a/o3d/core/cross/gl/renderer_gl.h
+++ b/o3d/core/cross/gl/renderer_gl.h
@@ -78,6 +78,14 @@ class RendererGL : public Renderer {
return fullscreen_;
}
+ // Get a vector of the available fullscreen display modes.
+ // Clears *modes on error.
+ virtual void GetDisplayModes(std::vector<DisplayMode> *modes);
+
+ // Get a single fullscreen display mode by id.
+ // Returns true on success, false on error.
+ virtual bool GetDisplayMode(int id, DisplayMode *mode);
+
// Resizes the viewport in OpenGL.
virtual void Resize(int width, int height);
diff --git a/o3d/core/cross/renderer.h b/o3d/core/cross/renderer.h
index c372bca..f299886 100644
--- a/o3d/core/cross/renderer.h
+++ b/o3d/core/cross/renderer.h
@@ -218,11 +218,8 @@ class Renderer {
// display: a platform-specific display identifier
// mode_id: a mode returned by GetDisplayModes
// Returns true on success, false on failure.
- // TODO(o3d): Make this pure virtual once it's implemented everywhere.
virtual bool GoFullscreen(const DisplayWindow& display,
- int mode_id) {
- return false;
- }
+ int mode_id) = 0;
// Cancels fullscreen display. Restores rendering to windowed mode
// with the given width and height.
@@ -231,27 +228,19 @@ class Renderer {
// width: the width to which to restore windowed rendering
// height: the height to which to restore windowed rendering
// Returns true on success, false on failure.
- // TODO(o3d): Make this pure virtual once it's implemented everywhere.
virtual bool CancelFullscreen(const DisplayWindow& display,
- int width, int height) {
- return false;
- }
+ int width, int height) = 0;
// Tells whether we're currently displayed fullscreen or not.
- virtual bool fullscreen() const { return false; }
+ virtual bool fullscreen() const = 0;
// Get a vector of the available fullscreen display modes.
// Clears *modes on error.
- // TODO: Make this pure virtual once it's implemented everywhere.
- virtual void GetDisplayModes(std::vector<DisplayMode> *modes) {
- modes->clear();
- }
+ virtual void GetDisplayModes(std::vector<DisplayMode> *modes) = 0;
+
// Get a single fullscreen display mode by id.
// Returns true on success, false on error.
- // TODO: Make this pure virtual once it's implemented everywhere.
- virtual bool GetDisplayMode(int id, DisplayMode *mode) {
- return false;
- }
+ virtual bool GetDisplayMode(int id, DisplayMode *mode) = 0;
// Gets the viewport.
void GetViewport(Float4* rectangle, Float2* depth_range);
diff --git a/o3d/plugin/cross/o3d_glue.cc b/o3d/plugin/cross/o3d_glue.cc
index 91a12f7..d041907 100644
--- a/o3d/plugin/cross/o3d_glue.cc
+++ b/o3d/plugin/cross/o3d_glue.cc
@@ -140,8 +140,13 @@ PluginObject::PluginObject(NPP npp)
xt_app_context_(NULL),
xt_interval_(0),
last_click_time_(0),
+ drawable_(0),
gtk_container_(NULL),
+ gtk_fullscreen_container_(NULL),
+ gtk_event_source_(NULL),
+ event_handler_id_(0),
timeout_id_(0),
+ fullscreen_pending_(false),
draw_(true),
in_plugin_(false),
#endif
diff --git a/o3d/plugin/cross/o3d_glue.h b/o3d/plugin/cross/o3d_glue.h
index bd02228..4d2a90c 100644
--- a/o3d/plugin/cross/o3d_glue.h
+++ b/o3d/plugin/cross/o3d_glue.h
@@ -218,8 +218,13 @@ class PluginObject: public NPObject {
}
bool got_dblclick() const { return got_dblclick_; }
void set_got_dblclick(bool got_dblclick) { got_dblclick_ = got_dblclick; }
-#endif
-#ifdef OS_MACOSX
+#elif defined(OS_LINUX)
+ void SetGtkEventSource(GtkWidget *widget);
+ gboolean OnGtkConfigure(GtkWidget *widget,
+ GdkEventConfigure *configure_event);
+ gboolean OnGtkDelete(GtkWidget *widget,
+ GdkEvent *configure);
+#elif defined(OS_MACOSX)
void SetFullscreenOverlayMacWindow(WindowRef window) {
mac_fullscreen_overlay_window_ = window;
}
@@ -284,9 +289,14 @@ class PluginObject: public NPObject {
Time last_click_time_;
// XEmbed mode
+ Window drawable_;
GtkWidget *gtk_container_;
+ GtkWidget *gtk_fullscreen_container_;
+ GtkWidget *gtk_event_source_;
+ gulong event_handler_id_;
bool got_double_click_[3];
guint timeout_id_;
+ bool fullscreen_pending_;
bool draw_;
bool in_plugin_;
@@ -348,9 +358,9 @@ class PluginObject: public NPObject {
// Make a region of the plugin area that will invoke fullscreen mode if
// clicked. The app developer is responsible for communicating this to the
- // user, as this region has no visible marker. The user is also responsible
- // for updating this region if the plugin gets resized, as we don't know
- // whether or how to scale it.
+ // user, as this region has no visible marker. The developer is also
+ // responsible for updating this region if the plugin gets resized, as we
+ // don't know whether or how to scale it.
// Fails if the mode_id supplied isn't valid. Returns true on success.
bool SetFullscreenClickRegion(int x, int y, int width, int height,
int mode_id);
diff --git a/o3d/plugin/linux/main_linux.cc b/o3d/plugin/linux/main_linux.cc
index fbb6495..45cc982 100644
--- a/o3d/plugin/linux/main_linux.cc
+++ b/o3d/plugin/linux/main_linux.cc
@@ -75,7 +75,6 @@ void LinuxTimer(XtPointer data, XtIntervalId* id) {
obj->draw_ = true;
if (obj->renderer()) {
if (obj->client()->render_mode() == o3d::Client::RENDERMODE_CONTINUOUS ||
-
obj->renderer()->need_to_render()) {
// NOTE: this draws no matter what instead of just invalidating the
@@ -467,6 +466,10 @@ static gboolean GtkHandleMouseButton(GtkWidget *widget,
event.set_type(Event::TYPE_DBLCLICK);
obj->client()->AddEventToQueue(event);
}
+ if (event.in_plugin() && event.type() == Event::TYPE_MOUSEDOWN &&
+ obj->HitFullscreenClickRegion(event.x(), event.y())) {
+ obj->RequestFullscreenDisplay();
+ }
return TRUE;
}
@@ -501,6 +504,12 @@ static gboolean GtkHandleKey(GtkWidget *widget,
event.set_type(Event::TYPE_KEYPRESS);
obj->client()->AddEventToQueue(event);
}
+ // No need to check for Alt+F4 because Gtk (or the window manager?) handles
+ // that and delivers a destroy event to us already.
+ if (event.type() == Event::TYPE_KEYDOWN &&
+ event.key_code() == 0x1B) { // escape
+ obj->CancelFullscreenDisplay();
+ }
return TRUE;
}
@@ -539,6 +548,7 @@ static gboolean GtkEventCallback(GtkWidget *widget,
GdkEvent *event,
gpointer user_data) {
PluginObject *obj = static_cast<PluginObject *>(user_data);
+ DLOG_ASSERT(widget == obj->gtk_event_source_);
switch (event->type) {
case GDK_EXPOSE:
if (GTK_WIDGET_DRAWABLE(widget)) {
@@ -568,16 +578,35 @@ static gboolean GtkEventCallback(GtkWidget *widget,
}
}
+static gboolean GtkConfigureEventCallback(GtkWidget *widget,
+ GdkEventConfigure *configure_event,
+ gpointer user_data) {
+ PluginObject *obj = static_cast<PluginObject *>(user_data);
+ return obj->OnGtkConfigure(widget, configure_event);
+}
+
+static gboolean GtkDeleteEventCallback(GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data) {
+ PluginObject *obj = static_cast<PluginObject *>(user_data);
+ return obj->OnGtkDelete(widget, event);
+}
+
static gboolean GtkTimeoutCallback(gpointer user_data) {
PluginObject *obj = static_cast<PluginObject *>(user_data);
obj->draw_ = true;
obj->client()->Tick();
if (obj->renderer()) {
if (obj->client()->render_mode() == o3d::Client::RENDERMODE_CONTINUOUS ||
-
obj->renderer()->need_to_render()) {
- gtk_widget_queue_draw(obj->gtk_container_);
+ GtkWidget *widget;
+ if (obj->fullscreen()) {
+ widget = obj->gtk_fullscreen_container_;
+ } else {
+ widget = obj->gtk_container_;
+ }
+ gtk_widget_queue_draw(widget);
}
}
return TRUE;
@@ -692,7 +721,15 @@ NPError NPP_Destroy(NPP instance, NPSavedData **save) {
gtk_widget_unref(obj->gtk_container_);
obj->gtk_container_ = NULL;
}
+ if (obj->gtk_fullscreen_container_) {
+ gtk_widget_destroy(obj->gtk_fullscreen_container_);
+ gtk_widget_unref(obj->gtk_fullscreen_container_);
+ obj->gtk_container_ = NULL;
+ }
+ obj->gtk_event_source_ = NULL;
+ obj->event_handler_id_ = 0;
obj->window_ = 0;
+ obj->drawable_ = 0;
obj->display_ = NULL;
obj->TearDown();
@@ -703,7 +740,6 @@ NPError NPP_Destroy(NPP instance, NPSavedData **save) {
return NPERR_NO_ERROR;
}
-
NPError NPP_SetWindow(NPP instance, NPWindow *window) {
HANDLE_CRASHES;
PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
@@ -719,18 +755,9 @@ NPError NPP_SetWindow(NPP instance, NPWindow *window) {
// a GtkPlug to go into it.
obj->gtk_container_ = gtk_plug_new(xwindow);
gtk_widget_set_double_buffered(obj->gtk_container_, FALSE);
- gtk_widget_add_events(obj->gtk_container_,
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_SCROLL_MASK |
- GDK_KEY_PRESS_MASK |
- GDK_KEY_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK |
- GDK_EXPOSURE_MASK |
- GDK_ENTER_NOTIFY_MASK |
- GDK_LEAVE_NOTIFY_MASK);
- g_signal_connect(G_OBJECT(obj->gtk_container_), "event",
- G_CALLBACK(GtkEventCallback), obj);
+ if (!obj->fullscreen()) {
+ obj->SetGtkEventSource(obj->gtk_container_);
+ }
gtk_widget_show(obj->gtk_container_);
drawable = GDK_WINDOW_XID(obj->gtk_container_->window);
obj->timeout_id_ = g_timeout_add(10, GtkTimeoutCallback, obj);
@@ -765,6 +792,7 @@ NPError NPP_SetWindow(NPP instance, NPWindow *window) {
obj->client()->Init();
obj->display_ = display;
obj->window_ = xwindow;
+ obj->drawable_ = drawable;
}
obj->Resize(window->width, window->height);
@@ -790,19 +818,136 @@ int16 NPP_HandleEvent(NPP instance, void *event) {
namespace glue {
namespace _o3d {
+void PluginObject::SetGtkEventSource(GtkWidget *widget) {
+ if (gtk_event_source_) {
+ g_signal_handler_disconnect(G_OBJECT(gtk_event_source_),
+ event_handler_id_);
+ }
+ gtk_event_source_ = widget;
+ if (gtk_event_source_) {
+ gtk_widget_add_events(gtk_event_source_,
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_SCROLL_MASK |
+ GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_EXPOSURE_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK);
+ event_handler_id_ = g_signal_connect(G_OBJECT(gtk_event_source_), "event",
+ G_CALLBACK(GtkEventCallback), this);
+ }
+}
+
+gboolean PluginObject::OnGtkConfigure(GtkWidget *widget,
+ GdkEventConfigure *configure_event) {
+ DLOG_ASSERT(widget == gtk_fullscreen_container_);
+ if (fullscreen_pending_) {
+ // Our fullscreen window has been placed and sized. Switch to it.
+ fullscreen_pending_ = false;
+ Window fullscreen_window =
+ GDK_WINDOW_XID(gtk_fullscreen_container_->window);
+ DisplayWindowLinux display;
+ display.set_display(display_);
+ display.set_window(fullscreen_window);
+ prev_width_ = renderer()->width();
+ prev_height_ = renderer()->height();
+ if (!renderer()->GoFullscreen(display, fullscreen_region_mode_id_)) {
+ gtk_widget_destroy(gtk_fullscreen_container_);
+ gtk_fullscreen_container_ = NULL;
+ // The return value is for whether we handled the event, not whether it
+ // was successful, so return TRUE event for error.
+ return TRUE;
+ }
+ SetGtkEventSource(gtk_fullscreen_container_);
+ }
+ renderer()->Resize(configure_event->width, configure_event->height);
+ client()->SendResizeEvent(renderer()->width(), renderer()->height(),
+ true);
+ fullscreen_ = true;
+ return TRUE;
+}
+
+gboolean PluginObject::OnGtkDelete(GtkWidget *widget,
+ GdkEvent *event) {
+ DLOG_ASSERT(widget == gtk_fullscreen_container_);
+ CancelFullscreenDisplay();
+ return TRUE;
+}
+
bool PluginObject::GetDisplayMode(int id, o3d::DisplayMode *mode) {
- return false;
+ return renderer()->GetDisplayMode(id, mode);
}
// TODO: Where should this really live? It's platform-specific, but in
// PluginObject, which mainly lives in cross/o3d_glue.h+cc.
-bool PluginObject::RequestFullscreenDisplay() {
- // TODO: Unimplemented.
- return false;
+bool PluginObject::RequestFullscreenDisplay() {
+ if (fullscreen_ || fullscreen_pending_) {
+ return false;
+ }
+ if (!g_xembed_support) {
+ // I tested every Linux browser I could that worked with our plugin and not
+ // a single one lacked XEmbed/Gtk2 support, so I don't think that case is
+ // worth implementing.
+ DLOG(ERROR) << "Fullscreen not supported without XEmbed/Gtk2; please use a "
+ "modern web browser";
+ return false;
+ }
+ GtkWidget *widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ // The returned object counts as both a widget and a window.
+ GtkWindow *window = GTK_WINDOW(widget);
+ // The window title shouldn't normally be visible, but the user will see it
+ // if they Alt+Tab to another app.
+ gtk_window_set_title(window, "O3D Application");
+ // Suppresses the title bar, resize controls, etc.
+ gtk_window_set_decorated(window, FALSE);
+ // Stops Gtk from writing an off-screen buffer to the display, which conflicts
+ // with our GL rendering.
+ gtk_widget_set_double_buffered(widget, FALSE);
+ GdkScreen *screen = gtk_window_get_screen(window);
+ // In the case of Xinerama or TwinView, these will be the dimensions of the
+ // whole desktop, which is wrong, but the window manager is smart enough to
+ // restrict our size to that of the main screen.
+ gint width = gdk_screen_get_width(screen);
+ gint height = gdk_screen_get_height(screen);
+ gtk_window_set_default_size(window, width, height);
+ // This is probably superfluous since we have already set an appropriate
+ // size, but let's do it anyway. It could still be relevant for some window
+ // managers.
+ gtk_window_fullscreen(window);
+ g_signal_connect(G_OBJECT(window), "configure-event",
+ G_CALLBACK(GtkConfigureEventCallback), this);
+ g_signal_connect(G_OBJECT(window), "delete-event",
+ G_CALLBACK(GtkDeleteEventCallback), this);
+ gtk_fullscreen_container_ = widget;
+ gtk_widget_show(widget);
+ // We defer switching to the new window until it gets displayed and assigned
+ // it's final dimensions in the configure-event.
+ fullscreen_pending_ = true;
+ return true;
}
void PluginObject::CancelFullscreenDisplay() {
- // TODO: Unimplemented.
+ if (!fullscreen_) {
+ return;
+ }
+ o3d::DisplayWindowLinux default_display;
+ default_display.set_display(display_);
+ default_display.set_window(drawable_);
+ if (!renderer()->CancelFullscreen(default_display,
+ prev_width_,
+ prev_height_)) {
+ return;
+ }
+ renderer()->Resize(prev_width_, prev_height_);
+ client()->SendResizeEvent(renderer()->width(), renderer()->height(),
+ false);
+ SetGtkEventSource(gtk_container_);
+ gtk_widget_destroy(gtk_fullscreen_container_);
+ gtk_widget_unref(gtk_fullscreen_container_);
+ gtk_fullscreen_container_ = NULL;
+ fullscreen_ = false;
}
} // namespace _o3d
} // namespace glue