summaryrefslogtreecommitdiffstats
path: root/chrome/browser/plugin_carbon_interpose_mac.cc
blob: 04434769478e65ee5de05c6d94686ad9cc6db027 (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
// 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 <Carbon/Carbon.h>

#include "base/gfx/rect.h"
#include "webkit/glue/plugins/fake_plugin_window_tracker_mac.h"

namespace webkit_glue {

void NotifyBrowserOfPluginSelectWindow(uint32 window_id, CGRect bounds);
void NotifyBrowserOfPluginShowWindow(uint32 window_id, CGRect bounds);
void NotifyBrowserOfPluginHideWindow(uint32 window_id, CGRect bounds);
void NotifyBrowserOfPluginDisposeWindow(uint32 window_id, CGRect bounds);

}

// The process that was frontmost when a plugin created a new window; generally
// we expect this to be the browser UI process.
static ProcessSerialNumber g_saved_front_process = { 0, 0 };

// Bring the plugin process to the front so that the user can see it.
// TODO: Make this an IPC to order the plugin process above the browser
// process but not necessarily the frontmost.
static void SwitchToPluginProcess() {
  ProcessSerialNumber this_process, front_process;
  if (GetCurrentProcess(&this_process) != noErr)
    return;
  if (GetFrontProcess(&front_process) != noErr)
    return;
  Boolean matched = false;
  if (SameProcess(&this_process, &front_process, &matched) != noErr)
    return;
  if (!matched) {
    // TODO: We may need to keep a stack, or at least check the total window
    // count, since this won't work if a plugin opens more than one window at
    // a time.
    g_saved_front_process = front_process;
    SetFrontProcess(&this_process);
  }
}

// If the plugin process is still the front process, bring the prior
// front process (normally this will be the browser process) back to
// the front.
// TODO: Make this an IPC message so that the browser can properly
// reactivate the window.
static void SwitchToSavedProcess() {
  ProcessSerialNumber this_process, front_process;
  if (GetCurrentProcess(&this_process) != noErr)
    return;
  if (GetFrontProcess(&front_process) != noErr)
    return;
  Boolean matched = false;
  if (SameProcess(&this_process, &front_process, &matched) != noErr)
    return;
  if (matched) {
    SetFrontProcess(&g_saved_front_process);
  }
}

#pragma mark -

static Boolean ChromePluginIsWindowHilited(WindowRef window) {
  // TODO(stuartmorgan): Always returning true (instead of the real answer,
  // which would be false) means that clicking works, but it's not correct
  // either. Ideally we need a way to find out if the delegate corresponds
  // to a browser window that is active.
  const WebPluginDelegateImpl* delegate =
      FakePluginWindowTracker::SharedInstance()->GetDelegateForFakeWindow(
          window);
  Boolean isHilited = delegate ? true : IsWindowHilited(window);
  return isHilited;
}

static CGRect CGRectForWindow(WindowRef window) {
  CGRect bounds = { { 0, 0 }, { 0, 0 } };
  HIWindowGetBounds(window, kWindowContentRgn, kHICoordSpace72DPIGlobal,
                    &bounds);
  return bounds;
}

static void ChromePluginSelectWindow(WindowRef window) {
  SwitchToPluginProcess();
  SelectWindow(window);
  webkit_glue::NotifyBrowserOfPluginSelectWindow(HIWindowGetCGWindowID(window),
                                                 CGRectForWindow(window));
}

static void ChromePluginShowWindow(WindowRef window) {
  SwitchToPluginProcess();
  ShowWindow(window);
  webkit_glue::NotifyBrowserOfPluginShowWindow(HIWindowGetCGWindowID(window),
                                               CGRectForWindow(window));
}

static void ChromePluginDisposeWindow(WindowRef window) {
  SwitchToSavedProcess();
  webkit_glue::NotifyBrowserOfPluginDisposeWindow(HIWindowGetCGWindowID(window),
                                                  CGRectForWindow(window));
  DisposeWindow(window);
}

static void ChromePluginHideWindow(WindowRef window) {
  SwitchToSavedProcess();
  webkit_glue::NotifyBrowserOfPluginHideWindow(HIWindowGetCGWindowID(window),
                                               CGRectForWindow(window));
  HideWindow(window);
}

#pragma mark -

struct interpose_substitution {
  const void* replacement;
  const void* original;
};

#define INTERPOSE_FUNCTION(function) \
    { reinterpret_cast<const void*>(ChromePlugin##function), \
      reinterpret_cast<const void*>(function) }

__attribute__((used)) static const interpose_substitution substitutions[]
    __attribute__((section("__DATA, __interpose"))) = {
  INTERPOSE_FUNCTION(IsWindowHilited),
  INTERPOSE_FUNCTION(SelectWindow),
  INTERPOSE_FUNCTION(ShowWindow),
  INTERPOSE_FUNCTION(DisposeWindow),
  INTERPOSE_FUNCTION(HideWindow),
};