The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

GtkWindow.vala in birdfont

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of birdfont/GtkWindow.vala.
Merge ../birdfont-2.x
1 /* 2 Copyright (C) 2012 2013 2014 2015 Johan Mattsson 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 using Cairo; 19 using Gtk; 20 using Gdk; 21 using BirdFont; 22 using WebKit; 23 using Gdk; 24 using Notify; 25 26 namespace BirdFont { 27 28 public class GtkWindow : Gtk.Window, NativeWindow { 29 30 Box list_box; 31 Box canvas_box; 32 33 WebView html_canvas; 34 ScrolledWindow html_box; 35 36 Box tab_box; 37 38 GlyphCanvasArea glyph_canvas_area; 39 40 Clipboard clipboard; 41 string clipboard_svg = ""; 42 string inkscape_clipboard = ""; 43 44 Scrollbar scrollbar; 45 bool scrollbar_supress_signal = false; 46 47 /** Text input and callbacks. */ 48 public static bool text_input_is_active = false; 49 TextListener text_listener = new TextListener ("", "", ""); 50 Label text_input_label; 51 Entry text_entry; 52 Box text_box; 53 Gtk.Button submit_text_button; 54 55 ToolboxCanvas toolbox; 56 57 Task background_task = new Task(idle); 58 59 public GtkWindow (string title) { 60 scrollbar = new Scrollbar (Orientation.VERTICAL, new Adjustment (0, 0, 1, 1, 0.01, 0.1)); 61 ((Gtk.Window)this).set_title ("BirdFont"); 62 } 63 64 public static void idle () { 65 } 66 67 public void init () { 68 Notify.init ("Fonts have been exported."); 69 70 clipboard = Clipboard.get_for_display (get_display (), Gdk.SELECTION_CLIPBOARD); 71 72 Signal.connect(this, "notify::is-active", (GLib.Callback) window_focus, null); 73 74 scrollbar.value_changed.connect (() => { 75 double p; 76 77 if (!scrollbar_supress_signal) { 78 p = scrollbar.get_value () / (1 - scrollbar.adjustment.page_size); 79 FontDisplay display = MainWindow.get_current_display (); 80 display.scroll_to (p); 81 } 82 }); 83 84 delete_event.connect (() => { 85 MenuTab.quit (); 86 return true; 87 }); 88 89 set_size_and_position (); 90 91 glyph_canvas_area = new GlyphCanvasArea (MainWindow.glyph_canvas); 92 93 html_canvas = new WebView (); 94 html_canvas.get_settings ().enable_default_context_menu = false; 95 96 html_box = new ScrolledWindow (null, null); 97 html_box.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC); 98 html_box.add (html_canvas); 99 100 MainWindow.get_tab_bar ().signal_tab_selected.connect ((f, tab) => { 101 string uri = ""; 102 string html = ""; 103 FontDisplay fd = tab.get_display (); 104 105 scrollbar.set_visible (fd.has_scrollbar ()); 106 107 if (fd.get_name () == "Preview") { 108 uri = Preview.get_uri (); 109 html = Preview.get_html_with_absolute_paths (); 110 111 try { 112 html_canvas.load_html (html, uri); 113 } catch (Error e) { 114 warning (e.message); 115 warning ("Failed to load html into canvas."); 116 } 117 118 // show the webview when loading has finished 119 html_box.set_visible (true); 120 glyph_canvas_area.set_visible (false); 121 } else { 122 html_box.set_visible (false); 123 glyph_canvas_area.set_visible (true); 124 } 125 }); 126 127 // Hide this canvas when window is realized and flip canvas 128 // visibility in tab selection signal. 129 html_canvas.draw.connect ((t, e) => { 130 glyph_canvas_area.set_visible (false); 131 return false; 132 }); 133 134 canvas_box = new Box (Orientation.HORIZONTAL, 0); 135 canvas_box.pack_start (glyph_canvas_area, true, true, 0); 136 canvas_box.pack_start (html_box, true, true, 0); 137 canvas_box.pack_start (scrollbar, false, true, 0); 138 139 submit_text_button = new Gtk.Button (); 140 submit_text_button.set_label ("Submit"); 141 text_input_label = new Label (" " + "Text"); 142 text_entry = new Entry (); 143 text_box = new Box (Orientation.HORIZONTAL, 6); 144 text_box.pack_start (text_input_label, false, false, 0); 145 text_box.pack_start (text_entry, true, true, 0); 146 text_box.pack_start (submit_text_button, false, false, 0); 147 148 text_entry.changed.connect (() => { 149 text_listener.signal_text_input (text_entry.text); 150 }); 151 152 submit_text_button.clicked.connect (() => { 153 text_listener.signal_submit (text_entry.text); 154 text_input_is_active = false; 155 }); 156 157 tab_box = new Box (Orientation.VERTICAL, 0); 158 159 tab_box.pack_start (new TabbarCanvas (MainWindow.get_tab_bar ()), false, false, 0); 160 tab_box.pack_start (text_box, false, false, 5); 161 tab_box.pack_start (canvas_box, true, true, 0); 162 163 toolbox = new ToolboxCanvas (MainWindow.get_toolbox ()); 164 list_box = new Box (Orientation.HORIZONTAL, 0); 165 list_box.pack_start (toolbox, false, false, 0); 166 list_box.pack_start (tab_box, true, true, 0); 167 168 Box vbox = new Box (Orientation.VERTICAL, 0); 169 vbox.pack_start(list_box, true, true, 0); 170 add (vbox); 171 172 try { 173 set_icon_from_file ((!) SearchPaths.find_file (null, "birdfont_window_icon.png").get_path ()); 174 } catch (GLib.Error e) { 175 warning (e.message); 176 } 177 178 key_press_event.connect ((t, event) => { 179 if (!GtkWindow.text_input_is_active) { 180 GtkWindow.reset_modifier (event.state); 181 TabContent.key_press (event.keyval); 182 } 183 184 return false; 185 }); 186 187 key_release_event.connect ((t, event) => { 188 if (!GtkWindow.text_input_is_active) { 189 TabContent.key_release (event.keyval); 190 } 191 192 return false; 193 }); 194 195 size_allocate.connect(() => { 196 GlyphCanvas.redraw (); 197 }); 198 199 show_all (); 200 201 scrollbar.set_visible (false); 202 203 hide_text_input (); 204 205 MainWindow.open_recent_files_tab (); 206 } 207 208 public void window_focus (void* data) { 209 TabContent.reset_modifier (); 210 } 211 212 public static void reset_modifier (ModifierType flags) { 213 if ((flags & ModifierType.CONTROL_MASK) == 0) { 214 TabContent.key_release (Key.CTRL_RIGHT); 215 TabContent.key_release (Key.CTRL_LEFT); 216 } 217 218 if ((flags & ModifierType.SHIFT_MASK) == 0) { 219 TabContent.key_release (Key.SHIFT_LEFT); 220 TabContent.key_release (Key.SHIFT_RIGHT); 221 } 222 223 if ((flags & ModifierType.MOD1_MASK) == 0) { 224 TabContent.key_release (Key.ALT_LEFT); 225 TabContent.key_release (Key.ALT_RIGHT); 226 } 227 228 if ((flags & ModifierType.MOD5_MASK) == 0) { 229 TabContent.key_release (Key.LOGO_LEFT); 230 TabContent.key_release (Key.LOGO_RIGHT); 231 } 232 } 233 234 public void font_loaded () { 235 Font f = BirdFont.get_current_font (); 236 set_title (@"$(f.full_name)"); 237 } 238 239 public void set_scrollbar_size (double size) { 240 scrollbar.adjustment.page_size = size; 241 scrollbar.set_visible (size != 0); 242 } 243 244 public void set_scrollbar_position (double position) { 245 scrollbar_supress_signal = true; 246 scrollbar.adjustment.value = position * (1 - scrollbar.adjustment.page_size); 247 scrollbar_supress_signal = false; 248 } 249 250 public void dump_clipboard_content (Clipboard clipboard, SelectionData selection_data) { 251 string d; 252 return_if_fail (!is_null (selection_data)); 253 d = (string) ((!) selection_data); 254 stdout.printf (d); 255 } 256 257 public void dump_clipboard_target (Clipboard clipboard, Atom[] atoms) { 258 foreach (Atom target in atoms) { 259 print ("Target: " + target.name () + "\n"); 260 clipboard.request_contents (target, dump_clipboard_content); 261 } 262 } 263 264 public void dump_clipboard () { 265 clipboard.request_targets (dump_clipboard_target); 266 } 267 268 public string get_clipboard_data () { 269 SelectionData? selection_data; 270 Atom target; 271 string? t; 272 273 target = Atom.intern_static_string ("image/x-inkscape-svg"); 274 selection_data = clipboard.wait_for_contents (target); 275 276 if (!is_null (selection_data)) { 277 return (string) (((!) selection_data).get_data ()); 278 } 279 280 t = clipboard.wait_for_text (); 281 if (t != null) { 282 return (!) t; 283 } 284 285 return ""; 286 } 287 288 public void set_inkscape_clipboard (string inkscape_clipboard_data) { 289 if (BirdFont.mac) { 290 clipboard.set_text (inkscape_clipboard_data, -1); 291 } else { 292 TargetEntry t = { "image/x-inkscape-svg", 0, 0 }; 293 TargetEntry[] targets = { t }; 294 inkscape_clipboard = inkscape_clipboard_data; 295 296 // we can not add data to this closure because the third argument 297 // is owner and not private data. 298 clipboard.set_with_owner (targets, 299 300 // obtain clipboard data 301 (clipboard, selection_data, info, owner) => { 302 Atom type; 303 uchar[] data = (uchar[])(!)((GtkWindow*)owner)->inkscape_clipboard.to_utf8 (); 304 type = Atom.intern_static_string ("image/x-inkscape-svg"); 305 selection_data.set (type, 8, data); 306 }, 307 308 // clear clipboard data 309 (clipboard, user_data) => { 310 }, 311 312 this); 313 } 314 } 315 316 public void set_clipboard_text (string text) { 317 clipboard.set_text (text, -1); 318 } 319 320 public string get_clipboard_text () { 321 string? t; 322 323 t = clipboard.wait_for_text (); 324 if (t != null) { 325 return ((!) t).dup (); 326 } 327 328 return "".dup (); 329 } 330 331 public void set_clipboard (string svg) { 332 TargetEntry t = { "image/svg+xml", 0, 0 }; 333 TargetEntry[] targets = { t }; 334 clipboard_svg = svg; 335 clipboard.set_with_owner (targets, 336 337 // obtain clipboard data 338 (clipboard, selection_data, info, owner) => { 339 Atom type; 340 uchar[] data = (uchar[])(!)((GtkWindow*)owner)->clipboard_svg.to_utf8 (); 341 type = Atom.intern_static_string ("image/svg+xml"); 342 selection_data.set (type, 0, data); 343 }, 344 345 // clear clipboard data 346 (clipboard, user_data) => { 347 }, 348 349 this); 350 } 351 352 public void update_window_size () { 353 int w, h; 354 get_size (out w, out h); 355 356 Preferences.set ("window_width", @"$w"); 357 Preferences.set ("window_height", @"$h"); 358 } 359 360 private void set_size_and_position () { 361 int w = Preferences.get_window_width (); 362 int h = Preferences.get_window_height (); 363 set_default_size (w, h); 364 } 365 366 public void quit () { 367 Gtk.main_quit (); 368 } 369 370 public void file_chooser (string title, FileChooser fc, uint flags) { 371 string? fn = null; 372 bool folder; 373 if (BirdFont.get_arguments () .has_argument ("--windows")) { 374 folder = (flags & FileChooser.DIRECTORY) > 0; 375 MenuTab.show_file_dialog_tab (title, fc, folder); 376 } else { 377 if ((flags & FileChooser.DIRECTORY) > 0) { 378 if ((flags & FileChooser.LOAD) > 0) { 379 fn = show_file_chooser (title, FileChooserAction.SELECT_FOLDER, Stock.OPEN); 380 } else if ((flags & FileChooser.SAVE) > 0) { 381 fn = show_file_chooser (title, FileChooserAction.SELECT_FOLDER, Stock.SAVE); 382 } else { 383 warning ("Open or save is not set."); 384 } 385 } else if ((flags & FileChooser.LOAD) > 0) { 386 fn = show_file_chooser (title, FileChooserAction.OPEN, Stock.OPEN); 387 } else if ((flags & FileChooser.SAVE) > 0) { 388 fn = show_file_chooser (title, FileChooserAction.SAVE, Stock.SAVE); 389 } else { 390 warning ("Unknown type"); 391 } 392 } 393 394 fc.selected (fn); 395 } 396 397 public string? show_file_chooser (string title, FileChooserAction action, string label) { 398 string? fn = null; 399 FileChooserDialog file_chooser = new FileChooserDialog (title, this, action, Stock.CANCEL, ResponseType.CANCEL, label, ResponseType.ACCEPT); 400 Font font = BirdFont.get_current_font (); 401 int i; 402 string last_folder; 403 404 last_folder = Preferences.get ("last_folder"); 405 406 try { 407 if (last_folder == "") { 408 file_chooser.set_current_folder_file (font.get_folder ()); 409 } else { 410 file_chooser.set_current_folder_file (File.new_for_path (last_folder)); 411 } 412 } catch (GLib.Error e) { 413 stderr.printf (e.message); 414 } 415 416 if (file_chooser.run () == ResponseType.ACCEPT) { 417 GlyphCanvas.redraw (); 418 fn = file_chooser.get_filename (); 419 } 420 421 file_chooser.destroy (); 422 423 if (fn != null) { 424 i = ((!) fn).last_index_of ("/"); 425 if (i > -1) { 426 last_folder = ((!) fn).substring (0, i); 427 Preferences.set ("last_folder", @"$last_folder"); 428 } 429 } 430 431 return fn; 432 } 433 434 public void hide_text_input () { 435 text_listener = new TextListener ("", "", ""); 436 text_box.hide (); 437 text_input_is_active = false; 438 } 439 440 public void set_text_listener (TextListener listener) { 441 text_listener = listener; 442 text_input_label.set_text (" " + listener.label); 443 submit_text_button.set_label (listener.button_label); 444 text_box.show (); 445 text_entry.set_text (listener.default_text); 446 text_entry.activate.connect (() => { 447 text_listener.signal_submit (text_entry.text); 448 text_input_is_active = false; 449 }); 450 text_entry.grab_focus (); 451 text_input_is_active = true; 452 } 453 454 public bool convert_to_png (string from, string to) { 455 Pixbuf pixbuf; 456 string folder; 457 int i; 458 459 try { 460 i = to.last_index_of ("/"); 461 if (i != -1) { 462 folder = to.substring (0, i); 463 DirUtils.create (folder, 0xFFFFFF); 464 } 465 466 pixbuf = new Pixbuf.from_file (from); 467 pixbuf.save (to, "png"); 468 } catch (GLib.Error e) { 469 warning (e.message); 470 return false; 471 } 472 473 return true; 474 } 475 476 public void run_background_thread (Task t) { 477 unowned Thread<void*> bg; 478 479 MenuTab.start_background_thread (); 480 background_task = t; 481 482 try { 483 bg = Thread.create<void*> (this.background_thread, true); 484 } catch (GLib.Error e) { 485 warning (e.message); 486 } 487 } 488 489 public void run_non_blocking_background_thread (Task t) { 490 unowned Thread<void*> bg; 491 492 try { 493 bg = Thread.create<void*> (t.perform_task, true); 494 } catch (GLib.Error e) { 495 warning (e.message); 496 } 497 } 498 499 public void* background_thread () { 500 background_task.run (); 501 MenuTab.stop_background_thread (); 502 return null; 503 } 504 505 /** Run export in a background thread. */ 506 public void export_font () { 507 unowned Thread<void*> export_thread; 508 509 MenuTab.start_background_thread (); 510 511 try { 512 export_thread = Thread.create<void*> (this.export_thread, true); 513 } catch (GLib.Error e) { 514 warning (e.message); 515 } 516 } 517 518 public void* export_thread () { 519 IdleSource idle = new IdleSource (); 520 521 ExportCallback.export_fonts (); 522 MenuTab.stop_background_thread (); 523 MenuTab.signal_file_exported (); 524 525 idle.set_callback (() => { 526 Notify.Notification export_notification; 527 export_notification = new Notify.Notification ("BirdFont", t_("Your fonts have been exported."), null); 528 export_notification.show (); 529 return false; 530 }); 531 idle.attach (null); 532 533 return null; 534 } 535 536 /** Load font in a background thread. */ 537 public void load () { 538 unowned Thread<void*> thread; 539 540 MenuTab.start_background_thread (); 541 542 try { 543 thread = Thread.create<void*> (this.loading_thread, true); 544 } catch (GLib.Error e) { 545 warning (e.message); 546 } 547 } 548 549 public void* loading_thread () { 550 BirdFont.get_current_font ().load (); 551 MenuTab.stop_background_thread (); 552 MenuTab.signal_file_loaded (); 553 return null; 554 } 555 556 /** Save font in a background thread. */ 557 public void save () { 558 unowned Thread<void*> thread; 559 560 MenuTab.start_background_thread (); 561 562 try { 563 thread = Thread.create<void*> (this.saving_thread, true); 564 } catch (GLib.Error e) { 565 warning (e.message); 566 } 567 } 568 569 public void* saving_thread () { 570 BirdFont.get_current_font ().save (); 571 MenuTab.stop_background_thread (); 572 MenuTab.signal_file_saved (); 573 return null; 574 } 575 576 public void load_background_image () { 577 unowned Thread<void*> thread; 578 579 MenuTab.start_background_thread (); 580 581 try { 582 thread = Thread.create<void*> (this.background_image_thread, true); 583 } catch (GLib.Error e) { 584 warning (e.message); 585 } 586 } 587 588 public void* background_image_thread () { 589 BackgroundTool.load_background_image (); 590 MenuTab.stop_background_thread (); 591 return null; 592 } 593 594 public bool can_export () { 595 return true; 596 } 597 598 public void set_cursor (int visible) { 599 if (visible != NativeWindow.VISIBLE) { 600 get_window ().set_cursor (new Cursor (CursorType.BLANK_CURSOR)); 601 } else { 602 get_window ().set_cursor (new Cursor (CursorType.ARROW)); 603 } 604 } 605 606 public double get_screen_scale () { 607 string? scale = Environment.get_variable ("GDK_SCALE"); 608 double factor; 609 610 if (scale == null) { 611 return 1; 612 } 613 614 if (double.try_parse ((!) scale, out factor)) { 615 return factor; 616 } 617 618 return 1; 619 } 620 } 621 622 class TabbarCanvas : DrawingArea { 623 TabBar tabbar; 624 625 public TabbarCanvas (TabBar tb) { 626 tabbar = tb; 627 628 add_events (EventMask.BUTTON_PRESS_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK); 629 630 motion_notify_event.connect ((t, e)=> { 631 Gtk.Allocation alloc; 632 tabbar.motion (e.x, e.y); 633 get_allocation (out alloc); 634 queue_draw_area (0, 0, alloc.width, alloc.height); 635 return true; 636 }); 637 638 button_press_event.connect ((t, e)=> { 639 Gtk.Allocation alloc; 640 get_allocation (out alloc); 641 GtkWindow.reset_modifier (e.state); 642 tabbar.select_tab_click (e.x, e.y, alloc.width, alloc.height); 643 queue_draw_area (0, 0, alloc.width, alloc.height); 644 return true; 645 }); 646 647 draw.connect ((t, e)=> { 648 Gtk.Allocation alloc; 649 Context cr; 650 StyleContext context; 651 Gdk.RGBA color; 652 653 cr = cairo_create (get_window ()); 654 get_allocation (out alloc); 655 656 context = get_style_context (); 657 context.add_class (STYLE_CLASS_BUTTON); 658 color = context.get_background_color (Gtk.StateFlags.NORMAL); 659 660 if (color.alpha > 0) { 661 tabbar.set_background_color (color.red, color.green, color.blue); 662 } 663 664 tabbar.draw (cr, alloc.width, alloc.height); 665 return true; 666 }); 667 668 tabbar.signal_tab_selected.connect ((t) => { 669 Gtk.Allocation alloc; 670 get_allocation (out alloc); 671 queue_draw_area (0, 0, alloc.width, alloc.height); 672 }); 673 674 tabbar.redraw_tab_bar.connect ((x, y, w, h) => { 675 queue_draw_area (x, y, w, h); 676 }); 677 678 set_size_request (20, 38); 679 } 680 681 } 682 683 class ToolboxCanvas : DrawingArea { 684 Toolbox tb; 685 686 public ToolboxCanvas (Toolbox toolbox) { 687 tb = toolbox; 688 689 realize.connect (() => { 690 Gtk.Allocation allocation; 691 get_allocation (out allocation); 692 Toolbox.allocation_width = allocation.width; 693 Toolbox.allocation_height = allocation.height; 694 Toolbox.redraw_tool_box (); 695 }); 696 697 tb.redraw.connect ((x, y, w, h) => { 698 queue_draw_area (x, y, w, h); 699 }); 700 701 button_press_event.connect ((se, e)=> { 702 if (e.type == EventType.2BUTTON_PRESS) { 703 tb.double_click (e.button, e.x, e.y); 704 } else { 705 tb.press (e.button, e.x, e.y); 706 } 707 return true; 708 }); 709 710 button_release_event.connect ((se, e)=> { 711 tb.release (e.button, e.x, e.y); 712 return true; 713 }); 714 715 motion_notify_event.connect ((sen, e)=> { 716 // FIXME: e.y is two pixels off in GTK under Gnome 717 tb.move (e.x, e.y); 718 return true; 719 }); 720 721 draw.connect ((t, e)=> { 722 Gtk.Allocation allocation; 723 get_allocation (out allocation); 724 725 Context cw = cairo_create(get_window()); 726 Toolbox.allocation_width = allocation.width; 727 Toolbox.allocation_height = allocation.height; 728 tb.draw (allocation.width, allocation.height, cw); 729 730 return true; 731 }); 732 733 scroll_event.connect ((t, e)=> { 734 if (e.direction == Gdk.ScrollDirection.UP) { 735 tb.scroll_up (e.x, e.y); 736 } else if (e.direction == Gdk.ScrollDirection.DOWN) { 737 tb.scroll_down (e.x, e.y); 738 } 739 return true; 740 }); 741 742 add_events (EventMask.BUTTON_PRESS_MASK | EventMask.BUTTON_RELEASE_MASK | EventMask.POINTER_MOTION_MASK | EventMask.LEAVE_NOTIFY_MASK | EventMask.SCROLL_MASK); 743 744 set_size_request (212, 100); 745 746 leave_notify_event.connect ((t, e)=> { 747 tb.reset_active_tool (); 748 return true; 749 }); 750 751 } 752 } 753 754 public class GlyphCanvasArea : DrawingArea { 755 GlyphCanvas glyph_canvas; 756 WidgetAllocation alloc = new WidgetAllocation (); 757 uint32 last_release = 0; 758 uint32 last_press = 0; 759 760 public GlyphCanvasArea (GlyphCanvas gc) { 761 int event_flags; 762 763 glyph_canvas = gc; 764 765 event_flags = EventMask.BUTTON_PRESS_MASK; 766 event_flags |= EventMask.BUTTON_RELEASE_MASK; 767 event_flags |= EventMask.POINTER_MOTION_MASK; 768 event_flags |= EventMask.LEAVE_NOTIFY_MASK; 769 event_flags |= EventMask.SCROLL_MASK; 770 771 add_events (event_flags); 772 773 bool button_down = false; 774 775 glyph_canvas.signal_redraw_area.connect ((x, y, w, h) => { 776 queue_draw_area ((int)x, (int)y, (int)w, (int)h); 777 }); 778 779 draw.connect ((t, e)=> { 780 Gtk.Allocation allocation; 781 get_allocation (out allocation); 782 783 alloc = new WidgetAllocation (); 784 785 alloc.width = allocation.width; 786 alloc.height = allocation.height; 787 alloc.x = allocation.x; 788 alloc.y = allocation.y; 789 790 Context cw = cairo_create (get_window()); 791 792 Surface s = new Surface.similar (cw.get_target (), Cairo.Content.COLOR_ALPHA, alloc.width, alloc.height); 793 Context c = new Context (s); 794 795 TabContent.draw (alloc, c); 796 797 cw.save (); 798 cw.set_source_surface (c.get_target (), 0, 0); 799 cw.paint (); 800 cw.restore (); 801 802 return true; 803 }); 804 805 button_press_event.connect ((t, e)=> { 806 GtkWindow.reset_modifier (e.state); 807 808 if (button_down) { 809 warning (@"Button already is down. $(e.button)"); 810 } 811 812 if (e.time < last_press) { 813 warning ("Discarding event."); 814 return true; 815 } 816 817 last_press = e.time; 818 819 if (e.type == EventType.BUTTON_PRESS) { 820 TabContent.button_press (e.button, e.x, e.y); 821 button_down = true; 822 } else if (e.type == EventType.2BUTTON_PRESS) { 823 TabContent.double_click (e.button, e.x, e.y); 824 } 825 826 return true; 827 }); 828 829 button_release_event.connect ((t, e)=> { 830 if (!button_down) { 831 warning (@"Button is not down $(e.button)"); 832 } 833 834 if (e.time < last_release) { 835 warning ("Discarding event."); 836 return true; 837 } 838 839 if (e.type == EventType.BUTTON_RELEASE) { 840 TabContent.button_release ((int) e.button, e.x, e.y); 841 last_release = e.time; 842 button_down = false; 843 } 844 845 return true; 846 }); 847 848 motion_notify_event.connect ((t, e)=> { 849 TabContent.motion_notify (e.x, e.y); 850 return true; 851 }); 852 853 scroll_event.connect ((t, e)=> { 854 if (e.direction == Gdk.ScrollDirection.UP) { 855 TabContent.scroll_wheel_up (e.x, e.y); 856 } else if (e.direction == Gdk.ScrollDirection.DOWN) { 857 TabContent.scroll_wheel_down (e.x, e.y) ; 858 } 859 860 TabContent.button_release (2, e.x, e.y); 861 return true; 862 }); 863 864 can_focus = true; 865 } 866 } 867 868 } 869