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