summaryrefslogtreecommitdiffstats
path: root/chrome/browser/plugin_carbon_interpose_mac.cc
blob: 1957f47c10901dc844a4f34c5f3fe54c7b1bc16b (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
// 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,
                                       bool modal);
void NotifyBrowserOfPluginShowWindow(uint32 window_id, CGRect bounds,
                                     bool modal);
void NotifyBrowserOfPluginHideWindow(uint32 window_id, CGRect bounds);
void NotifyBrowserOfPluginDisposeWindow(uint32 window_id, CGRect bounds);

}  // namespace webkit_glue

// 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) {
    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);
  }
}

// Checks to see if there are any plugin-opened windows still showing, and if
// not reactivates the saved process.
// Should be called after any window has been closed.
static void MaybeReactivateSavedProcess() {
  bool window_is_visible = false;
  WindowRef window = GetWindowList();
  while (window != NULL) {
    if (IsWindowVisible(window)) {
      window_is_visible = true;
      break;
    }
    window = GetNextWindow(window);
  }

  if (!window_is_visible)
    SwitchToSavedProcess();
}

// Returns true if the given window is modal.
static bool IsModalWindow(WindowRef window) {
  WindowModality modality = kWindowModalityNone;
  WindowRef modal_target = NULL;
  OSStatus status = GetWindowModality(window, &modality, &modal_target);
  return (status == noErr) && (modality != kWindowModalityNone);
}

#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),
                                                 IsModalWindow(window));
}

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

static void ChromePluginDisposeWindow(WindowRef window) {
  CGWindowID window_id = HIWindowGetCGWindowID(window);
  CGRect window_rect = CGRectForWindow(window);
  DisposeWindow(window);
  webkit_glue::NotifyBrowserOfPluginDisposeWindow(window_id, window_rect);
  MaybeReactivateSavedProcess();
}

static void ChromePluginHideWindow(WindowRef window) {
  CGWindowID window_id = HIWindowGetCGWindowID(window);
  CGRect window_rect = CGRectForWindow(window);
  HideWindow(window);
  webkit_glue::NotifyBrowserOfPluginHideWindow(window_id, window_rect);
  MaybeReactivateSavedProcess();
}

#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),
};