FireBreath  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Pages
PluginWindowX11.cpp
1 /**********************************************************\
2 Original Author: Richard Bateman (taxilian)
3 
4 Created: Nov 24, 2009
5 License: Dual license model; choose one of two:
6  New BSD License
7  http://www.opensource.org/licenses/bsd-license.php
8  - or -
9  GNU Lesser General Public License, version 2.1
10  http://www.gnu.org/licenses/lgpl-2.1.html
11 
12 Copyright 2009 Richard Bateman, Firebreath development team
13 \**********************************************************/
14 
15 #include "PluginEvents/X11Event.h"
16 #include "PluginEvents/GeneralEvents.h"
17 #include "PluginEvents/DrawingEvents.h"
18 #include "PluginEvents/MouseEvents.h"
19 #include "PluginEvents/KeyboardEvents.h"
20 #include "ConstructDefaultPluginWindows.h"
21 #include "logging.h"
22 #include "X11/KeyCodesX11.h"
23 
24 #include "PluginWindowX11.h"
25 
26 #if FB_GUI_DISABLED != 1
27 
28 #include "PluginEvents/X11NativeGdkEvent.h"
29 #include <gdk/gdkx.h>
30 
31 #endif
32 
33 // These match the numbers used in WebKit (WebFrameView.m).
34 const int cScrollbarPixelsPerLineStep = 40;
35 
36 FB::PluginWindowX11* FB::createPluginWindowX11(const FB::WindowContextX11& ctx)
37 {
38  return new FB::PluginWindowX11(ctx);
39 }
40 
41 using namespace FB;
42 
43 PluginWindowX11::PluginWindowX11(const WindowContextX11& ctx)
44  :
45 #if FB_GUI_DISABLED != 1
46  m_window(ctx.window),
47  m_browserWindow(0),
48  m_focus(false),
49 #endif
50  m_x(0), m_y(0), m_width(0), m_height(0), m_clipLeft(0), m_clipRight(0),
51  m_clipTop(0), m_clipBottom(0), m_handler_id(0)
52 {
53  FBLOG_INFO("FB.PluginWindowX11", "Creating new PluginWindowX11");
54 #if FB_GUI_DISABLED != 1
55  m_container = gtk_plug_new((GdkNativeWindow)ctx.window);
56  m_canvas = gtk_drawing_area_new();
57 #ifdef GTK_WIDGET_SET_FLAGS
58  GTK_WIDGET_SET_FLAGS(GTK_WIDGET(m_canvas), GTK_CAN_FOCUS);
59 #else // gtk+-2.22 or newer
60  gtk_widget_set_can_focus(GTK_WIDGET(m_canvas), true);
61 #endif
62 
63  gtk_widget_add_events(
64  m_canvas,
65  GDK_BUTTON_PRESS_MASK |
66  GDK_BUTTON_RELEASE_MASK |
67  GDK_KEY_PRESS_MASK |
68  GDK_KEY_RELEASE_MASK |
69  GDK_POINTER_MOTION_MASK |
70  GDK_POINTER_MOTION_HINT_MASK |
71  GDK_SCROLL_MASK |
72  GDK_EXPOSURE_MASK |
73  GDK_VISIBILITY_NOTIFY_MASK |
74  GDK_ENTER_NOTIFY_MASK |
75  GDK_LEAVE_NOTIFY_MASK |
76  GDK_FOCUS_CHANGE_MASK
77  );
78 
79  m_handler_id = g_signal_connect(G_OBJECT(m_canvas), "event", G_CALLBACK(&PluginWindowX11::_EventCallback), this);
80  gtk_widget_show(m_canvas);
81  gtk_container_add(GTK_CONTAINER(m_container), m_canvas);
82  gtk_widget_show(m_container);
83 #endif
84 }
85 
86 PluginWindowX11::~PluginWindowX11()
87 {
88 #if FB_GUI_DISABLED != 1
89  g_signal_handler_disconnect(G_OBJECT(m_canvas), m_handler_id);
90 #endif
91  FBLOG_INFO("FB.PluginWindowX11", "Destroying PluginWindowX11");
92 }
93 
94 void PluginWindowX11::getWindowPosition(int32_t &x, int32_t &y, uint32_t &w, uint32_t &h) const
95 {
96  x = m_x;
97  y = m_y;
98  w = m_width;
99  h = m_height;
100 }
101 
103 {
104  FB::Rect rect = {m_y, m_x, m_y+m_height, m_x+m_width};
105  return rect;
106 }
107 
108 void PluginWindowX11::setWindowPosition(int32_t x, int32_t y, uint32_t w, uint32_t h)
109 {
110  if (m_x != x
111  || m_y != y
112  || m_width != w
113  || m_height != h) {
114  m_x = x;
115  m_y = y;
116  m_width = w;
117  m_height = h;
118  ResizedEvent evt;
119  SendEvent(&evt);
120  }
121 }
122 
123 void PluginWindowX11::getWindowClipping(int32_t &t, int32_t &l, int32_t &b, int32_t &r) const
124 {
125  t = m_clipTop;
126  l = m_clipLeft;
127  b = m_clipBottom;
128  r = m_clipRight;
129 }
130 
132 {
133  FB::Rect rect = {m_clipTop, m_clipLeft, m_clipBottom, m_clipRight};
134  return rect;
135 }
136 
137 void PluginWindowX11::setWindowClipping(int32_t t, int32_t l, int32_t b, int32_t r)
138 {
139  if (m_clipTop != t
140  || m_clipLeft != l
141  || m_clipBottom != b
142  || m_clipRight != r) {
143  m_clipTop = t;
144  m_clipLeft = l;
145  m_clipBottom = b;
146  m_clipRight = r;
147  ClipChangedEvent evt;
148  SendEvent(&evt);
149  }
150 }
151 
152 #if FB_GUI_DISABLED != 1
153 
154 gboolean PluginWindowX11::_EventCallback(GtkWidget *widget, GdkEvent *event, gpointer user_data)
155 {
156  if (!user_data)
157  return 0;
158 
159  PluginWindowX11 *pluginWin = (PluginWindowX11 *)user_data;
160  return pluginWin->EventCallback(widget, event);
161 }
162 
163 inline bool isButtonEvent(GdkEvent *event)
164 {
165  switch(event->type) {
166  case GDK_BUTTON_PRESS:
167  case GDK_BUTTON_RELEASE:
168  case GDK_2BUTTON_PRESS:
169  case GDK_3BUTTON_PRESS:
170  return true;
171  default:
172  return false;
173  }
174 }
175 
176 inline unsigned int getModifierState(guint state) {
177  unsigned int modifierState = (state & GDK_SHIFT_MASK) != 0 ? MouseButtonEvent::ModifierState_Shift : 0;
178  modifierState += (state & GDK_CONTROL_MASK) != 0 ? MouseButtonEvent::ModifierState_Control : 0;
179  modifierState += (state & GDK_MOD1_MASK) != 0 ? MouseButtonEvent::ModifierState_Menu : 0;
180  return modifierState;
181 }
182 
183 gboolean PluginWindowX11::EventCallback(GtkWidget *widget, GdkEvent *event)
184 {
185  X11Event ev(widget, event);
186  if (SendEvent(&ev)) {
187  return true;
188  }
189 
190  switch(event->type)
191  {
192  case GDK_EXPOSE:
193  {
194  GdkEventExpose * exposeEvent = reinterpret_cast<GdkEventExpose *>(event);
195  FB::Rect rect;
196  rect.left = exposeEvent->area.x;
197  rect.top = exposeEvent->area.y;
198  rect.right = exposeEvent->area.x + exposeEvent->area.width;
199  rect.bottom = exposeEvent->area.y + exposeEvent->area.height;
200  RefreshEvent evt(rect);
201  return SendEvent(&evt) ? 1 : 0;
202  }
203  }
204 
205  GdkEventButton *button;
206  MouseButtonEvent::MouseButton btn;
207 
208  if (isButtonEvent(event)) {
209 
210  button = (GdkEventButton *)event;
211  switch(button->button) {
212  case 1:
213  btn = MouseButtonEvent::MouseButton_Left;
214  break;
215  case 2:
216  btn = MouseButtonEvent::MouseButton_Middle;
217  break;
218  case 3:
219  btn = MouseButtonEvent::MouseButton_Right;
220  break;
221  default:
222  return 0;
223  }
224  }
225 
226  switch(event->type)
227  {
228  // Mouse button down
229  case GDK_BUTTON_PRESS: {
230  MouseDownEvent evt(btn, button->x, button->y, getModifierState(button->state));
231  if(!m_focus){
232  //When the mouse button is pressed, we can be sure,
233  //that the top window has the focus and we can request keyboard focus.
234  gtk_widget_grab_focus(widget);
235  }
236  return SendEvent(&evt) ? 1 : 0;
237  } break;
238 
239  // Mouse button up
240  case GDK_2BUTTON_PRESS: {
241  MouseDoubleClickEvent evt(btn, button->x, button->y, getModifierState(button->state));
242  return SendEvent(&evt) ? 1 : 0;
243  } break;
244  // Mouse button up
245  case GDK_BUTTON_RELEASE: {
246  MouseUpEvent evt(btn, button->x, button->y, getModifierState(button->state));
247  return SendEvent(&evt) ? 1 : 0;
248  } break;
249 
250  case GDK_KEY_PRESS: {
251  GdkEventKey *key = (GdkEventKey *)event;
252  KeyDownEvent evt(GDKKeyCodeToFBKeyCode(key->keyval),key->keyval);
253  SendEvent(&evt) ? 1 : 0;
254  } break;
255 
256  case GDK_KEY_RELEASE: {
257  GdkEventKey *key = (GdkEventKey *)event;
258  KeyUpEvent evt(GDKKeyCodeToFBKeyCode(key->keyval),key->keyval);
259  SendEvent(&evt) ? 1 : 0;
260  } break;
261 
262  case GDK_MOTION_NOTIFY: {
263  GdkEventMotion *motion = (GdkEventMotion *)event;
264  MouseMoveEvent evt(motion->x, motion->y);
265  return SendEvent(&evt) ? 1 : 0;
266  } break;
267 
268  case GDK_SCROLL: {
269  GdkEventScroll *scroll = (GdkEventScroll *)event;
270  gdouble dx = 0;
271  gdouble dy = 0;
272  switch (scroll->direction)
273  {
274  case GDK_SCROLL_UP:
275  dy -= cScrollbarPixelsPerLineStep;
276  break;
277  case GDK_SCROLL_DOWN:
278  dy += cScrollbarPixelsPerLineStep;
279  break;
280  case GDK_SCROLL_LEFT:
281  dx -= cScrollbarPixelsPerLineStep;
282  break;
283  case GDK_SCROLL_RIGHT:
284  dx += cScrollbarPixelsPerLineStep;
285  break;
286  }
287  MouseScrollEvent evt(scroll->x, scroll->y, -dx, -dy, getModifierState(scroll->state));
288  return SendEvent(&evt) ? 1 : 0;
289  } break;
290 
291  case GDK_FOCUS_CHANGE: {
292  GdkEventFocus *focus = (GdkEventFocus *)event;
293  m_focus = focus->in ? true : false;
294  FocusChangedEvent evt(m_focus);
295  return SendEvent(&evt) ? 1 : 0;
296  }
297  default:
298  return false;
299  }
300 
301  return false;
302 }
303 
304 //
305 // int16_t PluginWindowX11::HandleEvent(EventRecord* evt)
306 // {
307 // // Give the plugin a change to handle the event itself if desired
308 // if (SendEvent(&MacEvent(evt))) {
309 // return true;
310 // }
311 // switch (evt->what) {
312 // case updateEvt:
313 // return SendEvent(&RefreshEvent());
314 // break;
315 // default:
316 // break;
317 // }
318 // return false;
319 // }
320 
321 GdkNativeWindow PluginWindowX11::getWindow()
322 {
323  return GDK_WINDOW_XID(getWidgetWindow());
324 //#if GTK_CHECK_VERSION(2, 14, 0)
325 // return GDK_WINDOW_XID(gtk_widget_get_window(m_canvas));
326 //#else
327 // return GDK_WINDOW_XID(GTK_WIDGET(m_canvas)->window);
328 //#endif
329 }
330 
331 GdkWindow* PluginWindowX11::getWidgetWindow() const
332 {
333 #if GTK_CHECK_VERSION(2, 14, 0)
334  return (gtk_widget_get_window(m_canvas));
335 #else
336  return (GTK_WIDGET(m_canvas)->window);
337 #endif
338 }
339 
340 #endif
341 
343 #if FB_GUI_DISABLED != 1
344  g_idle_add(idleInvalidate, const_cast<PluginWindowX11 *>(this));
345 #endif // FB_GUI_DISABLED != 1
346 }
347 
348 
349 #if FB_GUI_DISABLED != 1
350 gboolean PluginWindowX11::idleInvalidate(gpointer win) {
351  const PluginWindowX11 *w = reinterpret_cast<PluginWindowX11 *>(win);
352  gdk_window_invalidate_rect(w->getWidgetWindow(), NULL, true);
353  return FALSE;
354 }
355 #endif // FB_GUI_DISABLED != 1
FB::Rect getWindowPosition() const
Gets the position rect of the window.
Fired for a key down event.
Fired when the user moves the scrollwheel.
Definition: MouseEvents.h:116
Fired when the mouse moves.
Definition: MouseEvents.h:50
Fired when a mouse up event occurs.
Definition: MouseEvents.h:105
Fired when the clipping of the plugin drawing area changes.
Definition: DrawingEvents.h:45
X11 specific implementation of PluginWindow.
Generic X11 event.
Definition: X11Event.h:32
Fired when the focus changes.
Fired for a key up event.
FBKeyCode GDKKeyCodeToFBKeyCode(unsigned int key)
Converts a GDK key code to a FireBreath key code.
Definition: KeyCodesX11.cpp:23
Fired when a mouse down event occurs.
Definition: MouseEvents.h:83
virtual void InvalidateWindow() const
Invalidate window. This should tell the OS to send a REFRESH event.
Fired when the plugin should repaint itself (such as on windows when WM_PAINT is received) ...
Definition: DrawingEvents.h:55
FB::Rect getWindowClipping() const
Gets the clipping rect of the window.
virtual bool SendEvent(PluginEvent *evt)
Sends an event to all attached sinks.
Fired when a mouse double click event occurs.
Definition: MouseEvents.h:94
Fired when the plugin window is resized.
Definition: DrawingEvents.h:36