]> git.sesse.net Git - casparcg/blob - dependencies64/cef/linux/tests/cefclient/browser/browser_window_osr_gtk.cc
67775ecf70ee03406b43fba0f48c6a4147eb2387
[casparcg] / dependencies64 / cef / linux / tests / cefclient / browser / browser_window_osr_gtk.cc
1 // Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "tests/cefclient/browser/browser_window_osr_gtk.h"
6
7 #include <gdk/gdk.h>
8 #include <gdk/gdkkeysyms.h>
9 #include <gdk/gdkx.h>
10 #include <glib-object.h>
11 #include <gtk/gtk.h>
12 #include <gtk/gtkgl.h>
13 #include <GL/gl.h>
14
15 #define XK_3270  // for XK_3270_BackTab
16 #include <X11/keysym.h>
17 #include <X11/XF86keysym.h>
18 #include <X11/Xcursor/Xcursor.h>
19
20 #include "include/base/cef_logging.h"
21 #include "include/wrapper/cef_closure_task.h"
22 #include "tests/shared/browser/geometry_util.h"
23 #include "tests/shared/browser/main_message_loop.h"
24
25 namespace client {
26
27 namespace {
28
29 int GetCefStateModifiers(guint state) {
30   int modifiers = 0;
31   if (state & GDK_SHIFT_MASK)
32     modifiers |= EVENTFLAG_SHIFT_DOWN;
33   if (state & GDK_LOCK_MASK)
34     modifiers |= EVENTFLAG_CAPS_LOCK_ON;
35   if (state & GDK_CONTROL_MASK)
36     modifiers |= EVENTFLAG_CONTROL_DOWN;
37   if (state & GDK_MOD1_MASK)
38     modifiers |= EVENTFLAG_ALT_DOWN;
39   if (state & GDK_BUTTON1_MASK)
40     modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
41   if (state & GDK_BUTTON2_MASK)
42     modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
43   if (state & GDK_BUTTON3_MASK)
44     modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
45   return modifiers;
46 }
47
48 // From ui/events/keycodes/keyboard_codes_posix.h.
49 enum KeyboardCode {
50   VKEY_BACK = 0x08,
51   VKEY_TAB = 0x09,
52   VKEY_BACKTAB = 0x0A,
53   VKEY_CLEAR = 0x0C,
54   VKEY_RETURN = 0x0D,
55   VKEY_SHIFT = 0x10,
56   VKEY_CONTROL = 0x11,
57   VKEY_MENU = 0x12,
58   VKEY_PAUSE = 0x13,
59   VKEY_CAPITAL = 0x14,
60   VKEY_KANA = 0x15,
61   VKEY_HANGUL = 0x15,
62   VKEY_JUNJA = 0x17,
63   VKEY_FINAL = 0x18,
64   VKEY_HANJA = 0x19,
65   VKEY_KANJI = 0x19,
66   VKEY_ESCAPE = 0x1B,
67   VKEY_CONVERT = 0x1C,
68   VKEY_NONCONVERT = 0x1D,
69   VKEY_ACCEPT = 0x1E,
70   VKEY_MODECHANGE = 0x1F,
71   VKEY_SPACE = 0x20,
72   VKEY_PRIOR = 0x21,
73   VKEY_NEXT = 0x22,
74   VKEY_END = 0x23,
75   VKEY_HOME = 0x24,
76   VKEY_LEFT = 0x25,
77   VKEY_UP = 0x26,
78   VKEY_RIGHT = 0x27,
79   VKEY_DOWN = 0x28,
80   VKEY_SELECT = 0x29,
81   VKEY_PRINT = 0x2A,
82   VKEY_EXECUTE = 0x2B,
83   VKEY_SNAPSHOT = 0x2C,
84   VKEY_INSERT = 0x2D,
85   VKEY_DELETE = 0x2E,
86   VKEY_HELP = 0x2F,
87   VKEY_0 = 0x30,
88   VKEY_1 = 0x31,
89   VKEY_2 = 0x32,
90   VKEY_3 = 0x33,
91   VKEY_4 = 0x34,
92   VKEY_5 = 0x35,
93   VKEY_6 = 0x36,
94   VKEY_7 = 0x37,
95   VKEY_8 = 0x38,
96   VKEY_9 = 0x39,
97   VKEY_A = 0x41,
98   VKEY_B = 0x42,
99   VKEY_C = 0x43,
100   VKEY_D = 0x44,
101   VKEY_E = 0x45,
102   VKEY_F = 0x46,
103   VKEY_G = 0x47,
104   VKEY_H = 0x48,
105   VKEY_I = 0x49,
106   VKEY_J = 0x4A,
107   VKEY_K = 0x4B,
108   VKEY_L = 0x4C,
109   VKEY_M = 0x4D,
110   VKEY_N = 0x4E,
111   VKEY_O = 0x4F,
112   VKEY_P = 0x50,
113   VKEY_Q = 0x51,
114   VKEY_R = 0x52,
115   VKEY_S = 0x53,
116   VKEY_T = 0x54,
117   VKEY_U = 0x55,
118   VKEY_V = 0x56,
119   VKEY_W = 0x57,
120   VKEY_X = 0x58,
121   VKEY_Y = 0x59,
122   VKEY_Z = 0x5A,
123   VKEY_LWIN = 0x5B,
124   VKEY_COMMAND = VKEY_LWIN,  // Provide the Mac name for convenience.
125   VKEY_RWIN = 0x5C,
126   VKEY_APPS = 0x5D,
127   VKEY_SLEEP = 0x5F,
128   VKEY_NUMPAD0 = 0x60,
129   VKEY_NUMPAD1 = 0x61,
130   VKEY_NUMPAD2 = 0x62,
131   VKEY_NUMPAD3 = 0x63,
132   VKEY_NUMPAD4 = 0x64,
133   VKEY_NUMPAD5 = 0x65,
134   VKEY_NUMPAD6 = 0x66,
135   VKEY_NUMPAD7 = 0x67,
136   VKEY_NUMPAD8 = 0x68,
137   VKEY_NUMPAD9 = 0x69,
138   VKEY_MULTIPLY = 0x6A,
139   VKEY_ADD = 0x6B,
140   VKEY_SEPARATOR = 0x6C,
141   VKEY_SUBTRACT = 0x6D,
142   VKEY_DECIMAL = 0x6E,
143   VKEY_DIVIDE = 0x6F,
144   VKEY_F1 = 0x70,
145   VKEY_F2 = 0x71,
146   VKEY_F3 = 0x72,
147   VKEY_F4 = 0x73,
148   VKEY_F5 = 0x74,
149   VKEY_F6 = 0x75,
150   VKEY_F7 = 0x76,
151   VKEY_F8 = 0x77,
152   VKEY_F9 = 0x78,
153   VKEY_F10 = 0x79,
154   VKEY_F11 = 0x7A,
155   VKEY_F12 = 0x7B,
156   VKEY_F13 = 0x7C,
157   VKEY_F14 = 0x7D,
158   VKEY_F15 = 0x7E,
159   VKEY_F16 = 0x7F,
160   VKEY_F17 = 0x80,
161   VKEY_F18 = 0x81,
162   VKEY_F19 = 0x82,
163   VKEY_F20 = 0x83,
164   VKEY_F21 = 0x84,
165   VKEY_F22 = 0x85,
166   VKEY_F23 = 0x86,
167   VKEY_F24 = 0x87,
168   VKEY_NUMLOCK = 0x90,
169   VKEY_SCROLL = 0x91,
170   VKEY_LSHIFT = 0xA0,
171   VKEY_RSHIFT = 0xA1,
172   VKEY_LCONTROL = 0xA2,
173   VKEY_RCONTROL = 0xA3,
174   VKEY_LMENU = 0xA4,
175   VKEY_RMENU = 0xA5,
176   VKEY_BROWSER_BACK = 0xA6,
177   VKEY_BROWSER_FORWARD = 0xA7,
178   VKEY_BROWSER_REFRESH = 0xA8,
179   VKEY_BROWSER_STOP = 0xA9,
180   VKEY_BROWSER_SEARCH = 0xAA,
181   VKEY_BROWSER_FAVORITES = 0xAB,
182   VKEY_BROWSER_HOME = 0xAC,
183   VKEY_VOLUME_MUTE = 0xAD,
184   VKEY_VOLUME_DOWN = 0xAE,
185   VKEY_VOLUME_UP = 0xAF,
186   VKEY_MEDIA_NEXT_TRACK = 0xB0,
187   VKEY_MEDIA_PREV_TRACK = 0xB1,
188   VKEY_MEDIA_STOP = 0xB2,
189   VKEY_MEDIA_PLAY_PAUSE = 0xB3,
190   VKEY_MEDIA_LAUNCH_MAIL = 0xB4,
191   VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5,
192   VKEY_MEDIA_LAUNCH_APP1 = 0xB6,
193   VKEY_MEDIA_LAUNCH_APP2 = 0xB7,
194   VKEY_OEM_1 = 0xBA,
195   VKEY_OEM_PLUS = 0xBB,
196   VKEY_OEM_COMMA = 0xBC,
197   VKEY_OEM_MINUS = 0xBD,
198   VKEY_OEM_PERIOD = 0xBE,
199   VKEY_OEM_2 = 0xBF,
200   VKEY_OEM_3 = 0xC0,
201   VKEY_OEM_4 = 0xDB,
202   VKEY_OEM_5 = 0xDC,
203   VKEY_OEM_6 = 0xDD,
204   VKEY_OEM_7 = 0xDE,
205   VKEY_OEM_8 = 0xDF,
206   VKEY_OEM_102 = 0xE2,
207   VKEY_OEM_103 = 0xE3,  // GTV KEYCODE_MEDIA_REWIND
208   VKEY_OEM_104 = 0xE4,  // GTV KEYCODE_MEDIA_FAST_FORWARD
209   VKEY_PROCESSKEY = 0xE5,
210   VKEY_PACKET = 0xE7,
211   VKEY_DBE_SBCSCHAR = 0xF3,
212   VKEY_DBE_DBCSCHAR = 0xF4,
213   VKEY_ATTN = 0xF6,
214   VKEY_CRSEL = 0xF7,
215   VKEY_EXSEL = 0xF8,
216   VKEY_EREOF = 0xF9,
217   VKEY_PLAY = 0xFA,
218   VKEY_ZOOM = 0xFB,
219   VKEY_NONAME = 0xFC,
220   VKEY_PA1 = 0xFD,
221   VKEY_OEM_CLEAR = 0xFE,
222   VKEY_UNKNOWN = 0,
223
224   // POSIX specific VKEYs. Note that as of Windows SDK 7.1, 0x97-9F, 0xD8-DA,
225   // and 0xE8 are unassigned.
226   VKEY_WLAN = 0x97,
227   VKEY_POWER = 0x98,
228   VKEY_BRIGHTNESS_DOWN = 0xD8,
229   VKEY_BRIGHTNESS_UP = 0xD9,
230   VKEY_KBD_BRIGHTNESS_DOWN = 0xDA,
231   VKEY_KBD_BRIGHTNESS_UP = 0xE8,
232
233   // Windows does not have a specific key code for AltGr. We use the unused 0xE1
234   // (VK_OEM_AX) code to represent AltGr, matching the behaviour of Firefox on
235   // Linux.
236   VKEY_ALTGR = 0xE1,
237   // Windows does not have a specific key code for Compose. We use the unused
238   // 0xE6 (VK_ICO_CLEAR) code to represent Compose.
239   VKEY_COMPOSE = 0xE6,
240 };
241
242 // From ui/events/keycodes/keyboard_code_conversion_x.cc.
243 // Gdk key codes (e.g. GDK_BackSpace) and X keysyms (e.g. XK_BackSpace) share
244 // the same values.
245 KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym) {
246   switch (keysym) {
247     case XK_BackSpace:
248       return VKEY_BACK;
249     case XK_Delete:
250     case XK_KP_Delete:
251       return VKEY_DELETE;
252     case XK_Tab:
253     case XK_KP_Tab:
254     case XK_ISO_Left_Tab:
255     case XK_3270_BackTab:
256       return VKEY_TAB;
257     case XK_Linefeed:
258     case XK_Return:
259     case XK_KP_Enter:
260     case XK_ISO_Enter:
261       return VKEY_RETURN;
262     case XK_Clear:
263     case XK_KP_Begin:  // NumPad 5 without Num Lock, for crosbug.com/29169.
264       return VKEY_CLEAR;
265     case XK_KP_Space:
266     case XK_space:
267       return VKEY_SPACE;
268     case XK_Home:
269     case XK_KP_Home:
270       return VKEY_HOME;
271     case XK_End:
272     case XK_KP_End:
273       return VKEY_END;
274     case XK_Page_Up:
275     case XK_KP_Page_Up:  // aka XK_KP_Prior
276       return VKEY_PRIOR;
277     case XK_Page_Down:
278     case XK_KP_Page_Down:  // aka XK_KP_Next
279       return VKEY_NEXT;
280     case XK_Left:
281     case XK_KP_Left:
282       return VKEY_LEFT;
283     case XK_Right:
284     case XK_KP_Right:
285       return VKEY_RIGHT;
286     case XK_Down:
287     case XK_KP_Down:
288       return VKEY_DOWN;
289     case XK_Up:
290     case XK_KP_Up:
291       return VKEY_UP;
292     case XK_Escape:
293       return VKEY_ESCAPE;
294     case XK_Kana_Lock:
295     case XK_Kana_Shift:
296       return VKEY_KANA;
297     case XK_Hangul:
298       return VKEY_HANGUL;
299     case XK_Hangul_Hanja:
300       return VKEY_HANJA;
301     case XK_Kanji:
302       return VKEY_KANJI;
303     case XK_Henkan:
304       return VKEY_CONVERT;
305     case XK_Muhenkan:
306       return VKEY_NONCONVERT;
307     case XK_Zenkaku_Hankaku:
308       return VKEY_DBE_DBCSCHAR;
309     case XK_A:
310     case XK_a:
311       return VKEY_A;
312     case XK_B:
313     case XK_b:
314       return VKEY_B;
315     case XK_C:
316     case XK_c:
317       return VKEY_C;
318     case XK_D:
319     case XK_d:
320       return VKEY_D;
321     case XK_E:
322     case XK_e:
323       return VKEY_E;
324     case XK_F:
325     case XK_f:
326       return VKEY_F;
327     case XK_G:
328     case XK_g:
329       return VKEY_G;
330     case XK_H:
331     case XK_h:
332       return VKEY_H;
333     case XK_I:
334     case XK_i:
335       return VKEY_I;
336     case XK_J:
337     case XK_j:
338       return VKEY_J;
339     case XK_K:
340     case XK_k:
341       return VKEY_K;
342     case XK_L:
343     case XK_l:
344       return VKEY_L;
345     case XK_M:
346     case XK_m:
347       return VKEY_M;
348     case XK_N:
349     case XK_n:
350       return VKEY_N;
351     case XK_O:
352     case XK_o:
353       return VKEY_O;
354     case XK_P:
355     case XK_p:
356       return VKEY_P;
357     case XK_Q:
358     case XK_q:
359       return VKEY_Q;
360     case XK_R:
361     case XK_r:
362       return VKEY_R;
363     case XK_S:
364     case XK_s:
365       return VKEY_S;
366     case XK_T:
367     case XK_t:
368       return VKEY_T;
369     case XK_U:
370     case XK_u:
371       return VKEY_U;
372     case XK_V:
373     case XK_v:
374       return VKEY_V;
375     case XK_W:
376     case XK_w:
377       return VKEY_W;
378     case XK_X:
379     case XK_x:
380       return VKEY_X;
381     case XK_Y:
382     case XK_y:
383       return VKEY_Y;
384     case XK_Z:
385     case XK_z:
386       return VKEY_Z;
387
388     case XK_0:
389     case XK_1:
390     case XK_2:
391     case XK_3:
392     case XK_4:
393     case XK_5:
394     case XK_6:
395     case XK_7:
396     case XK_8:
397     case XK_9:
398       return static_cast<KeyboardCode>(VKEY_0 + (keysym - XK_0));
399
400     case XK_parenright:
401       return VKEY_0;
402     case XK_exclam:
403       return VKEY_1;
404     case XK_at:
405       return VKEY_2;
406     case XK_numbersign:
407       return VKEY_3;
408     case XK_dollar:
409       return VKEY_4;
410     case XK_percent:
411       return VKEY_5;
412     case XK_asciicircum:
413       return VKEY_6;
414     case XK_ampersand:
415       return VKEY_7;
416     case XK_asterisk:
417       return VKEY_8;
418     case XK_parenleft:
419       return VKEY_9;
420
421     case XK_KP_0:
422     case XK_KP_1:
423     case XK_KP_2:
424     case XK_KP_3:
425     case XK_KP_4:
426     case XK_KP_5:
427     case XK_KP_6:
428     case XK_KP_7:
429     case XK_KP_8:
430     case XK_KP_9:
431       return static_cast<KeyboardCode>(VKEY_NUMPAD0 + (keysym - XK_KP_0));
432
433     case XK_multiply:
434     case XK_KP_Multiply:
435       return VKEY_MULTIPLY;
436     case XK_KP_Add:
437       return VKEY_ADD;
438     case XK_KP_Separator:
439       return VKEY_SEPARATOR;
440     case XK_KP_Subtract:
441       return VKEY_SUBTRACT;
442     case XK_KP_Decimal:
443       return VKEY_DECIMAL;
444     case XK_KP_Divide:
445       return VKEY_DIVIDE;
446     case XK_KP_Equal:
447     case XK_equal:
448     case XK_plus:
449       return VKEY_OEM_PLUS;
450     case XK_comma:
451     case XK_less:
452       return VKEY_OEM_COMMA;
453     case XK_minus:
454     case XK_underscore:
455       return VKEY_OEM_MINUS;
456     case XK_greater:
457     case XK_period:
458       return VKEY_OEM_PERIOD;
459     case XK_colon:
460     case XK_semicolon:
461       return VKEY_OEM_1;
462     case XK_question:
463     case XK_slash:
464       return VKEY_OEM_2;
465     case XK_asciitilde:
466     case XK_quoteleft:
467       return VKEY_OEM_3;
468     case XK_bracketleft:
469     case XK_braceleft:
470       return VKEY_OEM_4;
471     case XK_backslash:
472     case XK_bar:
473       return VKEY_OEM_5;
474     case XK_bracketright:
475     case XK_braceright:
476       return VKEY_OEM_6;
477     case XK_quoteright:
478     case XK_quotedbl:
479       return VKEY_OEM_7;
480     case XK_ISO_Level5_Shift:
481       return VKEY_OEM_8;
482     case XK_Shift_L:
483     case XK_Shift_R:
484       return VKEY_SHIFT;
485     case XK_Control_L:
486     case XK_Control_R:
487       return VKEY_CONTROL;
488     case XK_Meta_L:
489     case XK_Meta_R:
490     case XK_Alt_L:
491     case XK_Alt_R:
492       return VKEY_MENU;
493     case XK_ISO_Level3_Shift:
494       return VKEY_ALTGR;
495     case XK_Multi_key:
496       return VKEY_COMPOSE;
497     case XK_Pause:
498       return VKEY_PAUSE;
499     case XK_Caps_Lock:
500       return VKEY_CAPITAL;
501     case XK_Num_Lock:
502       return VKEY_NUMLOCK;
503     case XK_Scroll_Lock:
504       return VKEY_SCROLL;
505     case XK_Select:
506       return VKEY_SELECT;
507     case XK_Print:
508       return VKEY_PRINT;
509     case XK_Execute:
510       return VKEY_EXECUTE;
511     case XK_Insert:
512     case XK_KP_Insert:
513       return VKEY_INSERT;
514     case XK_Help:
515       return VKEY_HELP;
516     case XK_Super_L:
517       return VKEY_LWIN;
518     case XK_Super_R:
519       return VKEY_RWIN;
520     case XK_Menu:
521       return VKEY_APPS;
522     case XK_F1:
523     case XK_F2:
524     case XK_F3:
525     case XK_F4:
526     case XK_F5:
527     case XK_F6:
528     case XK_F7:
529     case XK_F8:
530     case XK_F9:
531     case XK_F10:
532     case XK_F11:
533     case XK_F12:
534     case XK_F13:
535     case XK_F14:
536     case XK_F15:
537     case XK_F16:
538     case XK_F17:
539     case XK_F18:
540     case XK_F19:
541     case XK_F20:
542     case XK_F21:
543     case XK_F22:
544     case XK_F23:
545     case XK_F24:
546       return static_cast<KeyboardCode>(VKEY_F1 + (keysym - XK_F1));
547     case XK_KP_F1:
548     case XK_KP_F2:
549     case XK_KP_F3:
550     case XK_KP_F4:
551       return static_cast<KeyboardCode>(VKEY_F1 + (keysym - XK_KP_F1));
552
553     case XK_guillemotleft:
554     case XK_guillemotright:
555     case XK_degree:
556     // In the case of canadian multilingual keyboard layout, VKEY_OEM_102 is
557     // assigned to ugrave key.
558     case XK_ugrave:
559     case XK_Ugrave:
560     case XK_brokenbar:
561       return VKEY_OEM_102;  // international backslash key in 102 keyboard.
562
563     // When evdev is in use, /usr/share/X11/xkb/symbols/inet maps F13-18 keys
564     // to the special XF86XK symbols to support Microsoft Ergonomic keyboards:
565     // https://bugs.freedesktop.org/show_bug.cgi?id=5783
566     // In Chrome, we map these X key symbols back to F13-18 since we don't have
567     // VKEYs for these XF86XK symbols.
568     case XF86XK_Tools:
569       return VKEY_F13;
570     case XF86XK_Launch5:
571       return VKEY_F14;
572     case XF86XK_Launch6:
573       return VKEY_F15;
574     case XF86XK_Launch7:
575       return VKEY_F16;
576     case XF86XK_Launch8:
577       return VKEY_F17;
578     case XF86XK_Launch9:
579       return VKEY_F18;
580     case XF86XK_Refresh:
581     case XF86XK_History:
582     case XF86XK_OpenURL:
583     case XF86XK_AddFavorite:
584     case XF86XK_Go:
585     case XF86XK_ZoomIn:
586     case XF86XK_ZoomOut:
587       // ui::AcceleratorGtk tries to convert the XF86XK_ keysyms on Chrome
588       // startup. It's safe to return VKEY_UNKNOWN here since ui::AcceleratorGtk
589       // also checks a Gdk keysym. http://crbug.com/109843
590       return VKEY_UNKNOWN;
591     // For supporting multimedia buttons on a USB keyboard.
592     case XF86XK_Back:
593       return VKEY_BROWSER_BACK;
594     case XF86XK_Forward:
595       return VKEY_BROWSER_FORWARD;
596     case XF86XK_Reload:
597       return VKEY_BROWSER_REFRESH;
598     case XF86XK_Stop:
599       return VKEY_BROWSER_STOP;
600     case XF86XK_Search:
601       return VKEY_BROWSER_SEARCH;
602     case XF86XK_Favorites:
603       return VKEY_BROWSER_FAVORITES;
604     case XF86XK_HomePage:
605       return VKEY_BROWSER_HOME;
606     case XF86XK_AudioMute:
607       return VKEY_VOLUME_MUTE;
608     case XF86XK_AudioLowerVolume:
609       return VKEY_VOLUME_DOWN;
610     case XF86XK_AudioRaiseVolume:
611       return VKEY_VOLUME_UP;
612     case XF86XK_AudioNext:
613       return VKEY_MEDIA_NEXT_TRACK;
614     case XF86XK_AudioPrev:
615       return VKEY_MEDIA_PREV_TRACK;
616     case XF86XK_AudioStop:
617       return VKEY_MEDIA_STOP;
618     case XF86XK_AudioPlay:
619       return VKEY_MEDIA_PLAY_PAUSE;
620     case XF86XK_Mail:
621       return VKEY_MEDIA_LAUNCH_MAIL;
622     case XF86XK_LaunchA:  // F3 on an Apple keyboard.
623       return VKEY_MEDIA_LAUNCH_APP1;
624     case XF86XK_LaunchB:  // F4 on an Apple keyboard.
625     case XF86XK_Calculator:
626       return VKEY_MEDIA_LAUNCH_APP2;
627     case XF86XK_WLAN:
628       return VKEY_WLAN;
629     case XF86XK_PowerOff:
630       return VKEY_POWER;
631     case XF86XK_MonBrightnessDown:
632       return VKEY_BRIGHTNESS_DOWN;
633     case XF86XK_MonBrightnessUp:
634       return VKEY_BRIGHTNESS_UP;
635     case XF86XK_KbdBrightnessDown:
636       return VKEY_KBD_BRIGHTNESS_DOWN;
637     case XF86XK_KbdBrightnessUp:
638       return VKEY_KBD_BRIGHTNESS_UP;
639
640     // TODO(sad): some keycodes are still missing.
641   }
642   return VKEY_UNKNOWN;
643 }
644
645 // From content/browser/renderer_host/input/web_input_event_util_posix.cc.
646 KeyboardCode GdkEventToWindowsKeyCode(const GdkEventKey* event) {
647   static const unsigned int kHardwareCodeToGDKKeyval[] = {
648     0,                 // 0x00:
649     0,                 // 0x01:
650     0,                 // 0x02:
651     0,                 // 0x03:
652     0,                 // 0x04:
653     0,                 // 0x05:
654     0,                 // 0x06:
655     0,                 // 0x07:
656     0,                 // 0x08:
657     0,                 // 0x09: GDK_Escape
658     GDK_1,             // 0x0A: GDK_1
659     GDK_2,             // 0x0B: GDK_2
660     GDK_3,             // 0x0C: GDK_3
661     GDK_4,             // 0x0D: GDK_4
662     GDK_5,             // 0x0E: GDK_5
663     GDK_6,             // 0x0F: GDK_6
664     GDK_7,             // 0x10: GDK_7
665     GDK_8,             // 0x11: GDK_8
666     GDK_9,             // 0x12: GDK_9
667     GDK_0,             // 0x13: GDK_0
668     GDK_minus,         // 0x14: GDK_minus
669     GDK_equal,         // 0x15: GDK_equal
670     0,                 // 0x16: GDK_BackSpace
671     0,                 // 0x17: GDK_Tab
672     GDK_q,             // 0x18: GDK_q
673     GDK_w,             // 0x19: GDK_w
674     GDK_e,             // 0x1A: GDK_e
675     GDK_r,             // 0x1B: GDK_r
676     GDK_t,             // 0x1C: GDK_t
677     GDK_y,             // 0x1D: GDK_y
678     GDK_u,             // 0x1E: GDK_u
679     GDK_i,             // 0x1F: GDK_i
680     GDK_o,             // 0x20: GDK_o
681     GDK_p,             // 0x21: GDK_p
682     GDK_bracketleft,   // 0x22: GDK_bracketleft
683     GDK_bracketright,  // 0x23: GDK_bracketright
684     0,                 // 0x24: GDK_Return
685     0,                 // 0x25: GDK_Control_L
686     GDK_a,             // 0x26: GDK_a
687     GDK_s,             // 0x27: GDK_s
688     GDK_d,             // 0x28: GDK_d
689     GDK_f,             // 0x29: GDK_f
690     GDK_g,             // 0x2A: GDK_g
691     GDK_h,             // 0x2B: GDK_h
692     GDK_j,             // 0x2C: GDK_j
693     GDK_k,             // 0x2D: GDK_k
694     GDK_l,             // 0x2E: GDK_l
695     GDK_semicolon,     // 0x2F: GDK_semicolon
696     GDK_apostrophe,    // 0x30: GDK_apostrophe
697     GDK_grave,         // 0x31: GDK_grave
698     0,                 // 0x32: GDK_Shift_L
699     GDK_backslash,     // 0x33: GDK_backslash
700     GDK_z,             // 0x34: GDK_z
701     GDK_x,             // 0x35: GDK_x
702     GDK_c,             // 0x36: GDK_c
703     GDK_v,             // 0x37: GDK_v
704     GDK_b,             // 0x38: GDK_b
705     GDK_n,             // 0x39: GDK_n
706     GDK_m,             // 0x3A: GDK_m
707     GDK_comma,         // 0x3B: GDK_comma
708     GDK_period,        // 0x3C: GDK_period
709     GDK_slash,         // 0x3D: GDK_slash
710     0,                 // 0x3E: GDK_Shift_R
711     0,                 // 0x3F:
712     0,                 // 0x40:
713     0,                 // 0x41:
714     0,                 // 0x42:
715     0,                 // 0x43:
716     0,                 // 0x44:
717     0,                 // 0x45:
718     0,                 // 0x46:
719     0,                 // 0x47:
720     0,                 // 0x48:
721     0,                 // 0x49:
722     0,                 // 0x4A:
723     0,                 // 0x4B:
724     0,                 // 0x4C:
725     0,                 // 0x4D:
726     0,                 // 0x4E:
727     0,                 // 0x4F:
728     0,                 // 0x50:
729     0,                 // 0x51:
730     0,                 // 0x52:
731     0,                 // 0x53:
732     0,                 // 0x54:
733     0,                 // 0x55:
734     0,                 // 0x56:
735     0,                 // 0x57:
736     0,                 // 0x58:
737     0,                 // 0x59:
738     0,                 // 0x5A:
739     0,                 // 0x5B:
740     0,                 // 0x5C:
741     0,                 // 0x5D:
742     0,                 // 0x5E:
743     0,                 // 0x5F:
744     0,                 // 0x60:
745     0,                 // 0x61:
746     0,                 // 0x62:
747     0,                 // 0x63:
748     0,                 // 0x64:
749     0,                 // 0x65:
750     0,                 // 0x66:
751     0,                 // 0x67:
752     0,                 // 0x68:
753     0,                 // 0x69:
754     0,                 // 0x6A:
755     0,                 // 0x6B:
756     0,                 // 0x6C:
757     0,                 // 0x6D:
758     0,                 // 0x6E:
759     0,                 // 0x6F:
760     0,                 // 0x70:
761     0,                 // 0x71:
762     0,                 // 0x72:
763     GDK_Super_L,       // 0x73: GDK_Super_L
764     GDK_Super_R,       // 0x74: GDK_Super_R
765   };
766
767   // |windows_key_code| has to include a valid virtual-key code even when we
768   // use non-US layouts, e.g. even when we type an 'A' key of a US keyboard
769   // on the Hebrew layout, |windows_key_code| should be VK_A.
770   // On the other hand, |event->keyval| value depends on the current
771   // GdkKeymap object, i.e. when we type an 'A' key of a US keyboard on
772   // the Hebrew layout, |event->keyval| becomes GDK_hebrew_shin and this
773   // KeyboardCodeFromXKeysym() call returns 0.
774   // To improve compatibilty with Windows, we use |event->hardware_keycode|
775   // for retrieving its Windows key-code for the keys when the
776   // WebCore::windows_key_codeForEvent() call returns 0.
777   // We shouldn't use |event->hardware_keycode| for keys that GdkKeymap
778   // objects cannot change because |event->hardware_keycode| doesn't change
779   // even when we change the layout options, e.g. when we swap a control
780   // key and a caps-lock key, GTK doesn't swap their
781   // |event->hardware_keycode| values but swap their |event->keyval| values.
782   KeyboardCode windows_key_code =
783       KeyboardCodeFromXKeysym(event->keyval);
784   if (windows_key_code)
785     return windows_key_code;
786
787   if (event->hardware_keycode < arraysize(kHardwareCodeToGDKKeyval)) {
788     int keyval = kHardwareCodeToGDKKeyval[event->hardware_keycode];
789     if (keyval)
790       return KeyboardCodeFromXKeysym(keyval);
791   }
792
793   // This key is one that keyboard-layout drivers cannot change.
794   // Use |event->keyval| to retrieve its |windows_key_code| value.
795   return KeyboardCodeFromXKeysym(event->keyval);
796 }
797
798 // From content/browser/renderer_host/input/web_input_event_util_posix.cc.
799 KeyboardCode GetWindowsKeyCodeWithoutLocation(KeyboardCode key_code) {
800   switch (key_code) {
801     case VKEY_LCONTROL:
802     case VKEY_RCONTROL:
803       return VKEY_CONTROL;
804     case VKEY_LSHIFT:
805     case VKEY_RSHIFT:
806     return VKEY_SHIFT;
807     case VKEY_LMENU:
808     case VKEY_RMENU:
809       return VKEY_MENU;
810     default:
811       return key_code;
812   }
813 }
814
815 // From content/browser/renderer_host/input/web_input_event_builders_gtk.cc.
816 // Gets the corresponding control character of a specified key code. See:
817 // http://en.wikipedia.org/wiki/Control_characters
818 // We emulate Windows behavior here.
819 int GetControlCharacter(KeyboardCode windows_key_code, bool shift) {
820   if (windows_key_code >= VKEY_A && windows_key_code <= VKEY_Z) {
821     // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A
822     return windows_key_code - VKEY_A + 1;
823   }
824   if (shift) {
825     // following graphics chars require shift key to input.
826     switch (windows_key_code) {
827       // ctrl-@ maps to \x00 (Null byte)
828       case VKEY_2:
829         return 0;
830       // ctrl-^ maps to \x1E (Record separator, Information separator two)
831       case VKEY_6:
832         return 0x1E;
833       // ctrl-_ maps to \x1F (Unit separator, Information separator one)
834       case VKEY_OEM_MINUS:
835         return 0x1F;
836       // Returns 0 for all other keys to avoid inputting unexpected chars.
837       default:
838         return 0;
839     }
840   } else {
841     switch (windows_key_code) {
842       // ctrl-[ maps to \x1B (Escape)
843       case VKEY_OEM_4:
844         return 0x1B;
845       // ctrl-\ maps to \x1C (File separator, Information separator four)
846       case VKEY_OEM_5:
847         return 0x1C;
848       // ctrl-] maps to \x1D (Group separator, Information separator three)
849       case VKEY_OEM_6:
850         return 0x1D;
851       // ctrl-Enter maps to \x0A (Line feed)
852       case VKEY_RETURN:
853         return 0x0A;
854       // Returns 0 for all other keys to avoid inputting unexpected chars.
855       default:
856         return 0;
857     }
858   }
859 }
860
861 void GetWidgetRectInScreen(GtkWidget* widget, GdkRectangle* r) {
862   gint x, y, w, h;
863   GdkRectangle extents;
864
865   GdkWindow* window = gtk_widget_get_parent_window(widget);
866
867   // Get parent's left-top screen coordinates.
868   gdk_window_get_root_origin(window, &x, &y);
869   // Get parent's width and height.
870   gdk_drawable_get_size(window, &w, &h);
871   // Get parent's extents including decorations.
872   gdk_window_get_frame_extents(window, &extents);
873
874   // X and Y calculations assume that left, right and bottom border sizes are
875   // all the same.
876   const gint border = (extents.width - w) / 2;
877   r->x = x + border + widget->allocation.x;
878   r->y = y + (extents.height - h) - border + widget->allocation.y;
879   r->width = widget->allocation.width;
880   r->height = widget->allocation.height;
881 }
882
883 class ScopedGLContext {
884  public:
885   ScopedGLContext(GtkWidget* widget, bool swap_buffers)
886       : swap_buffers_(swap_buffers) {
887     GdkGLContext* glcontext = gtk_widget_get_gl_context(widget);
888     gldrawable_ = gtk_widget_get_gl_drawable(widget);
889     is_valid_ = gdk_gl_drawable_gl_begin(gldrawable_, glcontext);
890   }
891
892   virtual ~ScopedGLContext() {
893     if (is_valid_) {
894       gdk_gl_drawable_gl_end(gldrawable_);
895
896       if(swap_buffers_) {
897         if (gdk_gl_drawable_is_double_buffered(gldrawable_))
898           gdk_gl_drawable_swap_buffers(gldrawable_);
899         else
900           glFlush();
901       }
902     }
903   }
904
905   bool IsValid() const { return is_valid_; }
906
907  private:
908   bool swap_buffers_;
909   GdkGLDrawable* gldrawable_;
910   bool is_valid_;
911 };
912
913 }  // namespace
914
915 BrowserWindowOsrGtk::BrowserWindowOsrGtk(BrowserWindow::Delegate* delegate,
916                                          const std::string& startup_url,
917                                          const OsrRenderer::Settings& settings)
918     : BrowserWindow(delegate),
919       renderer_(settings),
920       glarea_(NULL),
921       hidden_(false),
922       gl_enabled_(false),
923       painting_popup_(false),
924       device_scale_factor_(1.0f) {
925   client_handler_ = new ClientHandlerOsr(this, this, startup_url);
926 }
927
928 void BrowserWindowOsrGtk::CreateBrowser(
929     ClientWindowHandle parent_handle,
930     const CefRect& rect,
931     const CefBrowserSettings& settings,
932     CefRefPtr<CefRequestContext> request_context) {
933   REQUIRE_MAIN_THREAD();
934
935   // Create the native window.
936   Create(parent_handle);
937
938   // Retrieve the X11 Window ID for the GTK parent window.
939   GtkWidget* window = gtk_widget_get_ancestor(
940       GTK_WIDGET(parent_handle), GTK_TYPE_WINDOW);
941   ::Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(window));
942   DCHECK(xwindow);
943
944   CefWindowInfo window_info;
945   window_info.SetAsWindowless(xwindow, renderer_.IsTransparent());
946
947   // Create the browser asynchronously.
948   CefBrowserHost::CreateBrowser(window_info, client_handler_,
949                                 client_handler_->startup_url(),
950                                 settings, request_context);
951 }
952
953 void BrowserWindowOsrGtk::GetPopupConfig(CefWindowHandle temp_handle,
954                                          CefWindowInfo& windowInfo,
955                                          CefRefPtr<CefClient>& client,
956                                          CefBrowserSettings& settings) {
957   // Note: This method may be called on any thread.
958   windowInfo.SetAsWindowless(temp_handle, renderer_.IsTransparent());
959   client = client_handler_;
960 }
961
962 void BrowserWindowOsrGtk::ShowPopup(ClientWindowHandle parent_handle,
963                                     int x, int y, size_t width, size_t height) {
964   REQUIRE_MAIN_THREAD();
965   DCHECK(browser_.get());
966
967   // Create the native window.
968   Create(parent_handle);
969
970   // Send resize notification so the compositor is assigned the correct
971   // viewport size and begins rendering.
972   browser_->GetHost()->WasResized();
973
974   Show();
975 }
976
977 void BrowserWindowOsrGtk::Show() {
978   REQUIRE_MAIN_THREAD();
979
980   if (hidden_) {
981     // Set the browser as visible.
982     browser_->GetHost()->WasHidden(false);
983     hidden_ = false;
984   }
985
986   // Give focus to the browser.
987   browser_->GetHost()->SendFocusEvent(true);
988 }
989
990 void BrowserWindowOsrGtk::Hide() {
991   REQUIRE_MAIN_THREAD();
992   
993   if (!browser_)
994     return;
995
996   // Remove focus from the browser.
997   browser_->GetHost()->SendFocusEvent(false);
998
999   if (!hidden_) {
1000     // Set the browser as hidden.
1001     browser_->GetHost()->WasHidden(true);
1002     hidden_ = true;
1003   }
1004 }
1005
1006 void BrowserWindowOsrGtk::SetBounds(int x, int y, size_t width, size_t height) {
1007   REQUIRE_MAIN_THREAD();
1008   // Nothing to do here. GTK will take care of positioning in the container.
1009 }
1010
1011 void BrowserWindowOsrGtk::SetFocus(bool focus) {
1012   REQUIRE_MAIN_THREAD();
1013   if (glarea_ && focus)
1014     gtk_widget_grab_focus(glarea_);
1015 }
1016
1017 void BrowserWindowOsrGtk::SetDeviceScaleFactor(float device_scale_factor) {
1018   REQUIRE_MAIN_THREAD();
1019   if (device_scale_factor == device_scale_factor_)
1020     return;
1021
1022   // Apply some sanity checks.
1023   if (device_scale_factor < 1.0f || device_scale_factor > 4.0f)
1024     return;
1025
1026   device_scale_factor_ = device_scale_factor;
1027
1028   if (browser_) {
1029     browser_->GetHost()->NotifyScreenInfoChanged();
1030     browser_->GetHost()->WasResized();
1031   }
1032 }
1033
1034 float BrowserWindowOsrGtk::GetDeviceScaleFactor() const {
1035   REQUIRE_MAIN_THREAD();
1036   return device_scale_factor_;
1037 }
1038
1039 ClientWindowHandle BrowserWindowOsrGtk::GetWindowHandle() const {
1040   REQUIRE_MAIN_THREAD();
1041   return glarea_;
1042 }
1043
1044 void BrowserWindowOsrGtk::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
1045   CEF_REQUIRE_UI_THREAD();
1046 }
1047
1048 void BrowserWindowOsrGtk::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
1049   CEF_REQUIRE_UI_THREAD();
1050   REQUIRE_MAIN_THREAD();
1051
1052   // Detach |this| from the ClientHandlerOsr.
1053   static_cast<ClientHandlerOsr*>(client_handler_.get())->DetachOsrDelegate();
1054
1055   // Disconnect all signal handlers that reference |this|.
1056   g_signal_handlers_disconnect_matched(glarea_, G_SIGNAL_MATCH_DATA, 0, 0,
1057       NULL, NULL, this);
1058
1059   DisableGL();
1060 }
1061
1062 bool BrowserWindowOsrGtk::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
1063                                             CefRect& rect) {
1064   CEF_REQUIRE_UI_THREAD();
1065   return false;
1066 }
1067
1068 bool BrowserWindowOsrGtk::GetViewRect(CefRefPtr<CefBrowser> browser,
1069                                       CefRect& rect) {
1070   CEF_REQUIRE_UI_THREAD();
1071   REQUIRE_MAIN_THREAD();
1072
1073   if (!glarea_)
1074     return false;
1075
1076   // The simulated screen and view rectangle are the same. This is necessary
1077   // for popup menus to be located and sized inside the view.
1078   rect.x = rect.y = 0;
1079   rect.width = DeviceToLogical(glarea_->allocation.width, device_scale_factor_);
1080   rect.height = DeviceToLogical(glarea_->allocation.height,
1081                                 device_scale_factor_);
1082   return true;
1083 }
1084
1085 bool BrowserWindowOsrGtk::GetScreenPoint(CefRefPtr<CefBrowser> browser,
1086                                          int viewX,
1087                                          int viewY,
1088                                          int& screenX,
1089                                          int& screenY) {
1090   CEF_REQUIRE_UI_THREAD();
1091   REQUIRE_MAIN_THREAD();
1092
1093   GdkRectangle screen_rect;
1094   GetWidgetRectInScreen(glarea_, &screen_rect);
1095   screenX = screen_rect.x + LogicalToDevice(viewX, device_scale_factor_);
1096   screenY = screen_rect.y + LogicalToDevice(viewY, device_scale_factor_);
1097   return true;
1098 }
1099
1100 bool BrowserWindowOsrGtk::GetScreenInfo(CefRefPtr<CefBrowser> browser,
1101                                         CefScreenInfo& screen_info) {
1102   CEF_REQUIRE_UI_THREAD();
1103
1104   CefRect view_rect;
1105   GetViewRect(browser, view_rect);
1106
1107   screen_info.device_scale_factor = device_scale_factor_;
1108
1109   // The screen info rectangles are used by the renderer to create and position
1110   // popups. Keep popups inside the view rectangle.
1111   screen_info.rect = view_rect;
1112   screen_info.available_rect = view_rect;
1113   return true;
1114 }
1115
1116 void BrowserWindowOsrGtk::OnPopupShow(CefRefPtr<CefBrowser> browser,
1117                                       bool show) {
1118   CEF_REQUIRE_UI_THREAD();
1119   REQUIRE_MAIN_THREAD();
1120
1121   if (!show) {
1122     renderer_.ClearPopupRects();
1123     browser->GetHost()->Invalidate(PET_VIEW);
1124   }
1125   renderer_.OnPopupShow(browser, show);
1126 }
1127
1128 void BrowserWindowOsrGtk::OnPopupSize(CefRefPtr<CefBrowser> browser,
1129                                       const CefRect& rect) {
1130   CEF_REQUIRE_UI_THREAD();
1131   REQUIRE_MAIN_THREAD();
1132
1133   renderer_.OnPopupSize(browser, LogicalToDevice(rect, device_scale_factor_));
1134 }
1135
1136 void BrowserWindowOsrGtk::OnPaint(
1137     CefRefPtr<CefBrowser> browser,
1138     CefRenderHandler::PaintElementType type,
1139     const CefRenderHandler::RectList& dirtyRects,
1140     const void* buffer,
1141     int width,
1142     int height) {
1143   CEF_REQUIRE_UI_THREAD();
1144   REQUIRE_MAIN_THREAD();
1145
1146   if (width <= 2 && height <= 2) {
1147     // Ignore really small buffer sizes while the widget is starting up.
1148     return;
1149   }
1150
1151   if (painting_popup_) {
1152     renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
1153     return;
1154   }
1155
1156   if (!gl_enabled_)
1157     EnableGL();
1158
1159   ScopedGLContext scoped_gl_context(glarea_, true);
1160   if (!scoped_gl_context.IsValid())
1161     return;
1162
1163   renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
1164   if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) {
1165     painting_popup_ = true;
1166     browser->GetHost()->Invalidate(PET_POPUP);
1167     painting_popup_ = false;
1168   }
1169   renderer_.Render();
1170 }
1171
1172 void BrowserWindowOsrGtk::OnCursorChange(
1173     CefRefPtr<CefBrowser> browser,
1174     CefCursorHandle cursor,
1175     CefRenderHandler::CursorType type,
1176     const CefCursorInfo& custom_cursor_info) {
1177   CEF_REQUIRE_UI_THREAD();
1178   REQUIRE_MAIN_THREAD();
1179
1180   // Retrieve the X11 display shared with Chromium.
1181   ::Display* xdisplay = cef_get_xdisplay();
1182   DCHECK(xdisplay);
1183
1184   // Retrieve the X11 window handle for the GTK widget.
1185   ::Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(glarea_));
1186
1187   // Set the cursor.
1188   XDefineCursor(xdisplay, xwindow, cursor);
1189 }
1190
1191 bool BrowserWindowOsrGtk::StartDragging(
1192     CefRefPtr<CefBrowser> browser,
1193     CefRefPtr<CefDragData> drag_data,
1194     CefRenderHandler::DragOperationsMask allowed_ops,
1195     int x, int y) {
1196   CEF_REQUIRE_UI_THREAD();
1197   // TODO(port): Implement drag&drop support.
1198   return false;
1199 }
1200
1201 void BrowserWindowOsrGtk::UpdateDragCursor(
1202     CefRefPtr<CefBrowser> browser,
1203     CefRenderHandler::DragOperation operation) {
1204   CEF_REQUIRE_UI_THREAD();
1205 }
1206
1207 void BrowserWindowOsrGtk::OnImeCompositionRangeChanged(
1208     CefRefPtr<CefBrowser> browser,
1209     const CefRange& selection_range,
1210     const CefRenderHandler::RectList& character_bounds) {
1211   CEF_REQUIRE_UI_THREAD();
1212 }
1213
1214 void BrowserWindowOsrGtk::Create(ClientWindowHandle parent_handle) {
1215   REQUIRE_MAIN_THREAD();
1216   DCHECK(!glarea_);
1217
1218   glarea_ = gtk_drawing_area_new();
1219   DCHECK(glarea_);
1220
1221   GdkGLConfig* glconfig = gdk_gl_config_new_by_mode(
1222       static_cast<GdkGLConfigMode>(GDK_GL_MODE_RGB |
1223                                    GDK_GL_MODE_DEPTH |
1224                                    GDK_GL_MODE_DOUBLE));
1225   DCHECK(glconfig);
1226
1227   gtk_widget_set_gl_capability(glarea_, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE);
1228
1229   gtk_widget_set_can_focus(glarea_, TRUE);
1230
1231   g_signal_connect(G_OBJECT(glarea_), "size_allocate",
1232                    G_CALLBACK(&BrowserWindowOsrGtk::SizeAllocation), this);
1233
1234   gtk_widget_set_events(glarea_,
1235                         GDK_BUTTON_PRESS_MASK |
1236                         GDK_BUTTON_RELEASE_MASK |
1237                         GDK_KEY_PRESS_MASK |
1238                         GDK_KEY_RELEASE_MASK |
1239                         GDK_ENTER_NOTIFY_MASK |
1240                         GDK_LEAVE_NOTIFY_MASK |
1241                         GDK_POINTER_MOTION_MASK |
1242                         GDK_POINTER_MOTION_HINT_MASK |
1243                         GDK_SCROLL_MASK |
1244                         GDK_FOCUS_CHANGE_MASK);
1245   g_signal_connect(G_OBJECT(glarea_), "button_press_event",
1246                    G_CALLBACK(&BrowserWindowOsrGtk::ClickEvent), this);
1247   g_signal_connect(G_OBJECT(glarea_), "button_release_event",
1248                    G_CALLBACK(&BrowserWindowOsrGtk::ClickEvent), this);
1249   g_signal_connect(G_OBJECT(glarea_), "key_press_event",
1250                    G_CALLBACK(&BrowserWindowOsrGtk::KeyEvent), this);
1251   g_signal_connect(G_OBJECT(glarea_), "key_release_event",
1252                    G_CALLBACK(&BrowserWindowOsrGtk::KeyEvent), this);
1253   g_signal_connect(G_OBJECT(glarea_), "enter_notify_event",
1254                    G_CALLBACK(&BrowserWindowOsrGtk::MoveEvent), this);
1255   g_signal_connect(G_OBJECT(glarea_), "leave_notify_event",
1256                    G_CALLBACK(&BrowserWindowOsrGtk::MoveEvent), this);
1257   g_signal_connect(G_OBJECT(glarea_), "motion_notify_event",
1258                    G_CALLBACK(&BrowserWindowOsrGtk::MoveEvent), this);
1259   g_signal_connect(G_OBJECT(glarea_), "scroll_event",
1260                    G_CALLBACK(&BrowserWindowOsrGtk::ScrollEvent), this);
1261   g_signal_connect(G_OBJECT(glarea_), "focus_in_event",
1262                    G_CALLBACK(&BrowserWindowOsrGtk::FocusEvent), this);
1263   g_signal_connect(G_OBJECT(glarea_), "focus_out_event",
1264                    G_CALLBACK(&BrowserWindowOsrGtk::FocusEvent), this);
1265
1266   gtk_container_add(GTK_CONTAINER(parent_handle), glarea_);
1267
1268   // Make the GlArea visible in the parent container.
1269   gtk_widget_show_all(parent_handle);
1270 }
1271
1272 // static
1273 gint BrowserWindowOsrGtk::SizeAllocation(GtkWidget* widget,
1274                                          GtkAllocation* allocation,
1275                                          BrowserWindowOsrGtk* self) {
1276   REQUIRE_MAIN_THREAD();
1277
1278   if (self->browser_.get()) {
1279     // Results in a call to GetViewRect().
1280     self->browser_->GetHost()->WasResized();
1281   }
1282   return TRUE;
1283 }
1284
1285 // static
1286 gint BrowserWindowOsrGtk::ClickEvent(GtkWidget* widget,
1287                                      GdkEventButton* event,
1288                                      BrowserWindowOsrGtk* self) {
1289   REQUIRE_MAIN_THREAD();
1290
1291   if (!self->browser_.get())
1292     return TRUE;
1293
1294   CefRefPtr<CefBrowserHost> host = self->browser_->GetHost();
1295
1296   CefBrowserHost::MouseButtonType button_type = MBT_LEFT;
1297   switch (event->button) {
1298     case 1:
1299       break;
1300     case 2:
1301       button_type = MBT_MIDDLE;
1302       break;
1303     case 3:
1304       button_type = MBT_RIGHT;
1305       break;
1306     default:
1307       // Other mouse buttons are not handled here.
1308       return FALSE;
1309   }
1310
1311   CefMouseEvent mouse_event;
1312   mouse_event.x = event->x;
1313   mouse_event.y = event->y;
1314   self->ApplyPopupOffset(mouse_event.x, mouse_event.y);
1315   DeviceToLogical(mouse_event, self->device_scale_factor_);
1316   mouse_event.modifiers = GetCefStateModifiers(event->state);
1317
1318   bool mouse_up = (event->type == GDK_BUTTON_RELEASE);
1319   if (!mouse_up)
1320     gtk_widget_grab_focus(widget);
1321
1322   int click_count = 1;
1323   switch (event->type) {
1324     case GDK_2BUTTON_PRESS:
1325       click_count = 2;
1326       break;
1327     case GDK_3BUTTON_PRESS:
1328       click_count = 3;
1329       break;
1330     default:
1331       break;
1332   }
1333
1334   host->SendMouseClickEvent(mouse_event, button_type, mouse_up, click_count);
1335   return TRUE;
1336 }
1337
1338 // static
1339 gint BrowserWindowOsrGtk::KeyEvent(GtkWidget* widget,
1340                                    GdkEventKey* event,
1341                                    BrowserWindowOsrGtk* self) {
1342   REQUIRE_MAIN_THREAD();
1343
1344   if (!self->browser_.get())
1345     return TRUE;
1346
1347   CefRefPtr<CefBrowserHost> host = self->browser_->GetHost();
1348
1349   // Based on WebKeyboardEventBuilder::Build from
1350   // content/browser/renderer_host/input/web_input_event_builders_gtk.cc.
1351   CefKeyEvent key_event;
1352   KeyboardCode windows_key_code = GdkEventToWindowsKeyCode(event);
1353   key_event.windows_key_code =
1354       GetWindowsKeyCodeWithoutLocation(windows_key_code);
1355   key_event.native_key_code = event->hardware_keycode;
1356
1357   key_event.modifiers = GetCefStateModifiers(event->state);
1358   if (event->keyval >= GDK_KP_Space && event->keyval <= GDK_KP_9)
1359     key_event.modifiers |= EVENTFLAG_IS_KEY_PAD;
1360   if (key_event.modifiers & EVENTFLAG_ALT_DOWN)
1361     key_event.is_system_key = true;
1362
1363   if (windows_key_code == VKEY_RETURN) {
1364     // We need to treat the enter key as a key press of character \r.  This
1365     // is apparently just how webkit handles it and what it expects.
1366     key_event.unmodified_character = '\r';
1367   } else {
1368     // FIXME: fix for non BMP chars
1369     key_event.unmodified_character =
1370         static_cast<int>(gdk_keyval_to_unicode(event->keyval));
1371   }
1372
1373   // If ctrl key is pressed down, then control character shall be input.
1374   if (key_event.modifiers & EVENTFLAG_CONTROL_DOWN) {
1375     key_event.character =
1376       GetControlCharacter(windows_key_code,
1377                           key_event.modifiers & EVENTFLAG_SHIFT_DOWN);
1378   } else {
1379     key_event.character = key_event.unmodified_character;
1380   }
1381
1382   if (event->type == GDK_KEY_PRESS) {
1383     key_event.type = KEYEVENT_RAWKEYDOWN;
1384     host->SendKeyEvent(key_event);
1385     key_event.type = KEYEVENT_CHAR;
1386     host->SendKeyEvent(key_event);
1387   } else {
1388     key_event.type = KEYEVENT_KEYUP;
1389     host->SendKeyEvent(key_event);
1390   }
1391
1392   return TRUE;
1393 }
1394
1395 // static
1396 gint BrowserWindowOsrGtk::MoveEvent(GtkWidget* widget,
1397                                     GdkEventMotion* event,
1398                                     BrowserWindowOsrGtk* self) {
1399   REQUIRE_MAIN_THREAD();
1400
1401   if (!self->browser_.get())
1402     return TRUE;
1403
1404   CefRefPtr<CefBrowserHost> host = self->browser_->GetHost();
1405
1406   gint x, y;
1407   GdkModifierType state;
1408
1409   if (event->is_hint) {
1410     gdk_window_get_pointer(event->window, &x, &y, &state);
1411   } else {
1412     x = (gint)event->x;
1413     y = (gint)event->y;
1414     state = (GdkModifierType)event->state;
1415   }
1416
1417   CefMouseEvent mouse_event;
1418   mouse_event.x = x;
1419   mouse_event.y = y;
1420   self->ApplyPopupOffset(mouse_event.x, mouse_event.y);
1421   DeviceToLogical(mouse_event, self->device_scale_factor_);
1422   mouse_event.modifiers = GetCefStateModifiers(state);
1423
1424   bool mouse_leave = (event->type == GDK_LEAVE_NOTIFY);
1425
1426   host->SendMouseMoveEvent(mouse_event, mouse_leave);
1427   return TRUE;
1428 }
1429
1430 // static
1431 gint BrowserWindowOsrGtk::ScrollEvent(GtkWidget* widget,
1432                                       GdkEventScroll* event,
1433                                       BrowserWindowOsrGtk* self) {
1434   REQUIRE_MAIN_THREAD();
1435
1436   if (!self->browser_.get())
1437     return TRUE;
1438
1439   CefRefPtr<CefBrowserHost> host = self->browser_->GetHost();
1440
1441   CefMouseEvent mouse_event;
1442   mouse_event.x = event->x;
1443   mouse_event.y = event->y;
1444   self->ApplyPopupOffset(mouse_event.x, mouse_event.y);
1445   DeviceToLogical(mouse_event, self->device_scale_factor_);
1446   mouse_event.modifiers = GetCefStateModifiers(event->state);
1447
1448   static const int scrollbarPixelsPerGtkTick = 40;
1449   int deltaX = 0;
1450   int deltaY = 0;
1451   switch (event->direction) {
1452     case GDK_SCROLL_UP:
1453       deltaY = scrollbarPixelsPerGtkTick;
1454       break;
1455     case GDK_SCROLL_DOWN:
1456       deltaY = -scrollbarPixelsPerGtkTick;
1457       break;
1458     case GDK_SCROLL_LEFT:
1459       deltaX = scrollbarPixelsPerGtkTick;
1460       break;
1461     case GDK_SCROLL_RIGHT:
1462       deltaX = -scrollbarPixelsPerGtkTick;
1463       break;
1464   }
1465
1466   host->SendMouseWheelEvent(mouse_event, deltaX, deltaY);
1467   return TRUE;
1468 }
1469
1470 // static
1471 gint BrowserWindowOsrGtk::FocusEvent(GtkWidget* widget,
1472                                      GdkEventFocus* event,
1473                                      BrowserWindowOsrGtk* self) {
1474   REQUIRE_MAIN_THREAD();
1475
1476   if (self->browser_.get())
1477      self->browser_->GetHost()->SendFocusEvent(event->in == TRUE);
1478   return TRUE;
1479 }
1480
1481 bool BrowserWindowOsrGtk::IsOverPopupWidget(int x, int y) const {
1482   const CefRect& rc = renderer_.popup_rect();
1483   int popup_right = rc.x + rc.width;
1484   int popup_bottom = rc.y + rc.height;
1485   return (x >= rc.x) && (x < popup_right) &&
1486          (y >= rc.y) && (y < popup_bottom);
1487 }
1488
1489 int BrowserWindowOsrGtk::GetPopupXOffset() const {
1490   return renderer_.original_popup_rect().x - renderer_.popup_rect().x;
1491 }
1492
1493 int BrowserWindowOsrGtk::GetPopupYOffset() const {
1494   return renderer_.original_popup_rect().y - renderer_.popup_rect().y;
1495 }
1496
1497 void BrowserWindowOsrGtk::ApplyPopupOffset(int& x, int& y) const {
1498   if (IsOverPopupWidget(x, y)) {
1499     x += GetPopupXOffset();
1500     y += GetPopupYOffset();
1501   }
1502 }
1503
1504 void BrowserWindowOsrGtk::EnableGL() {
1505   REQUIRE_MAIN_THREAD();
1506
1507   if (gl_enabled_)
1508     return;
1509
1510   ScopedGLContext scoped_gl_context(glarea_, false);
1511   if (!scoped_gl_context.IsValid())
1512     return;
1513
1514   renderer_.Initialize();
1515
1516   gl_enabled_ = true;
1517 }
1518
1519 void BrowserWindowOsrGtk::DisableGL() {
1520   REQUIRE_MAIN_THREAD();
1521
1522   if (!gl_enabled_)
1523     return;
1524
1525   ScopedGLContext scoped_gl_context(glarea_, false);
1526   if (!scoped_gl_context.IsValid())
1527     return;
1528
1529   renderer_.Cleanup();
1530
1531   gl_enabled_ = false;
1532 }
1533
1534 }  // namespace client