Portál AbcLinuxu, 6. května 2025 08:51
Dnes objevil sem zajímavý programovací jazyk jménem Vala. Je trochu podobný C# a má vcelku jednu zajímavou vlastnost - umí generovat C kód (sice je místy trošku ošklivější) a ten pak ptohání gcc. Výsledný program je pak, narozdíl od C#, rychlý. A jelikož jsem nedávno dělal buttonek, přepsal jsem ho do tohoto jazyka.
Šlo to docela dobře, až na špatné "vapi" pro Gtk.Container.forall, takže je v souboru gtk+-2.0.vapi (obvykle v /usr/share/vala/vapi) nutno upravit argumenty z "Gtk.Callback callback" na "bool include_internals, Gtk.Callback callback" (někdo může nahlásit bug jestli není, mně se nechce). Kvůli téhle chybě mi to pořád padalo na SIGSEGV a když jsem tu metodu nepřekryl, tak mi to nechtělo kreslit buttonek a já se s tím tak dlouho trápil ...
MenuButton.vala:
using Gtk; public class Controls.MenuButton: Gtk.Container { weak Gtk.Widget _button_widget; Gtk.Menu? _menu; Gtk.HBox box; Gtk.Arrow? arrow; Gtk.Alignment? alignment; Gtk.ToggleButton toggle_button; weak Gtk.Widget size_widget; construct { set_flags (WidgetFlags.NO_WINDOW); _button_widget = null; _menu = null; arrow = null; alignment = null; toggle_button = new ToggleButton (); box = new HBox (false, 0); toggle_button.set_parent (this); box.set_parent (this); toggle_button.set_focus_on_click (false); toggle_button.set_relief (ReliefStyle.NONE); toggle_button.activate += on_toggle_activated; toggle_button.button_press_event += on_toggle_press_event; toggle_button.show (); box.show (); size_widget = toggle_button; } public MenuButton () { show_arrow = true; } public void remove_button_widget () { if (_button_widget == null) return; if (arrow != null) { box.remove (_button_widget); } else { toggle_button.remove (_button_widget); } _button_widget = null; } public Widget? button_widget { get { return _button_widget; } set { remove_button_widget (); if (value != null) { _button_widget = value; if (arrow != null) { box.pack_start (_button_widget, true, true, 0); } else { toggle_button.add (_button_widget); } } } } public bool show_arrow { get { return (arrow != null); } set { if (value) { if (arrow == null) { arrow = new Arrow (ArrowType.DOWN, ShadowType.NONE); alignment = new Alignment (0.0f, 0.5f, 0.0f, 0.0f); alignment.add (arrow); arrow.show (); alignment.show (); box.pack_end (alignment, false, false, 5); if (_button_widget != null) { _button_widget.ref (); toggle_button.remove (_button_widget); box.pack_start (_button_widget, true, true, 0); _button_widget.unref (); } size_widget = box; } } else if (arrow != null) { box.remove (alignment); arrow = null; alignment = null; if (_button_widget != null) { _button_widget.ref (); box.remove (_button_widget); toggle_button.add (_button_widget); _button_widget.unref (); } size_widget = toggle_button; } } } private void menu_position_func (Menu menu, out int x, out int y, out bool push_in) { Requisition menu_req = Requisition (); menu.size_request (out menu_req); Gdk.Screen screen; screen = get_screen (); int monitor_num = screen.get_monitor_at_window (window); Gdk.Rectangle monitor = Gdk.Rectangle (); screen.get_monitor_geometry (monitor_num < 0 ? 0 : monitor_num, out monitor); window.get_origin (out x, out y); y += allocation.y; x += allocation.x + int.max (allocation.width - menu_req.width, 0); if (y + allocation.height + menu_req.height <= monitor.y + monitor.height) { y += allocation.height; } else if (y - menu_req.height >= monitor.y) { y -= menu_req.height; } else if (monitor.y + monitor.height - (y + allocation.height) > y) { y += allocation.height; } else { y -= menu_req.height; } push_in = false; } private void show_menu () { _menu.popup (null, null, menu_position_func, 0, get_current_event_time ()); } private bool on_toggle_press_event (ToggleButton? toggle, Gdk.EventButton? but) { if (but.button == 1) { if (_menu != null) { show_menu (); toggle_button.set_active (true); } return true; } else return false; } private void on_toggle_activated (ToggleButton? toggle) { show_menu (); } private void on_menu_deactivate (Menu? menu) { toggle_button.set_active (false); } public Menu? menu { get { return _menu; } set { remove_menu (); if (value != null) { _menu = value; _menu.deactivate += on_menu_deactivate; } } } public void remove_menu () { if (_menu != null) { _menu.deactivate -= on_menu_deactivate; _menu = null; } } public override void size_allocate (Gdk.Rectangle allocation) { box.size_allocate (allocation); toggle_button.size_allocate (allocation); base.size_allocate (allocation); } public override void size_request (out Gtk.Requisition req) { size_widget.size_request (out req); } public override void add (Widget w) { } public override void remove (Widget w) { } public override void forall (bool include_internals, Gtk.Callback cb) { cb (toggle_button); cb (box); } }
Tiskni
Sdílej:
Výsledný program je pak, narozdíl od C#, rychlý.IMHO spis naopak, objektovy kod v C nemuze byt o moc rychlejsi nez v C# (oboji je runtime), zato treba C++ uz rychly je.
Právě že předpokládá, že jsou dobřít řádově stejně. g++ je nástroj na statickou analýzu objektového kódu a generování efektivního strojáku. Znásilnit k něčemu takovému překladač plain C není možné.
Ale zase když v C++ budete používat virtuální metody a výjimky, tak to taky bude "runtime", takže ono to vyjde celkem na stejno.
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.