"Fossies" - the Fresh Open Source Software Archive

Member "gambas-3.16.3/gb.gtk/src/gcontrol.cpp" (7 Sep 2021, 57872 Bytes) of package /linux/misc/gambas-3.16.3.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gcontrol.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.16.2_vs_3.16.3.

    1 /***************************************************************************
    2 
    3     gcontrol.cpp
    4 
    5     (c) 2004-2006 - Daniel Campos Fernández <dcamposf@gmail.com>
    6 
    7     This program is free software; you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation; either version 2, or (at your option)
   10     any later version.
   11 
   12     This program is distributed in the hope that it will be useful,
   13     but WITHOUT ANY WARRANTY; without even the implied warranty of
   14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15     GNU General Public License for more details.
   16 
   17     You should have received a copy of the GNU General Public License
   18     along with this program; if not, write to the Free Software
   19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   20     MA 02110-1301, USA.
   21 
   22 ***************************************************************************/
   23 
   24 #include <unistd.h>
   25 
   26 #include "widgets.h"
   27 #include "gapplication.h"
   28 #include "gbutton.h"
   29 #include "gdrawingarea.h"
   30 #include "gmainwindow.h"
   31 #include "gscrollbar.h"
   32 #include "gslider.h"
   33 #include "gdesktop.h"
   34 #include "gdrag.h"
   35 #include "gmouse.h"
   36 #include "gmenu.h"
   37 
   38 #ifndef GTK3
   39 #include "gplugin.h"
   40 #endif
   41 
   42 #include "gcontrol.h"
   43 
   44 //#define DEBUG_FOCUS 1
   45 //#define DEBUG_ENTER_LEAVE 1
   46 //#define DEBUG_DESTROY 1
   47 
   48 static GList *_destroy_list = NULL;
   49 
   50 #if 0
   51 static const char *_cursor_fdiag[] =
   52 {
   53 "16 16 4 1",
   54 "# c None",
   55 "a c #000000",
   56 "b c #c0c0c0",
   57 ". c #ffffff",
   58 "..........######",
   59 ".aaaaaaaa.######",
   60 ".a....ba.#######",
   61 ".a...ba.########",
   62 ".a....ab.#######",
   63 ".a.b...ab.######",
   64 ".abaa...ab.###..",
   65 ".aa.ba...ab.#.a.",
   66 ".a.#.ba...ab.aa.",
   67 "..###.ba...aaba.",
   68 "######.ba...b.a.",
   69 "#######.ba....a.",
   70 "########.ab...a.",
   71 "#######.ab....a.",
   72 "######.aaaaaaaa.",
   73 "######.........."
   74 };
   75 
   76 static const char *_cursor_bdiag[] =
   77 {
   78 "16 16 4 1",
   79 ". c None",
   80 "a c #000000",
   81 "b c #c0c0c0",
   82 "# c #ffffff",
   83 "......##########",
   84 "......#aaaaaaaa#",
   85 ".......#ab####a#",
   86 "........#ab###a#",
   87 ".......#ba####a#",
   88 "......#ba###b#a#",
   89 "##...#ba###aaba#",
   90 "#a#.#ba###ab#aa#",
   91 "#aa#ba###ab#.#a#",
   92 "#abaa###ab#...##",
   93 "#a#b###ab#......",
   94 "#a####ab#.......",
   95 "#a###ba#........",
   96 "#a####ba#.......",
   97 "#aaaaaaaa#......",
   98 "##########......"
   99 };
  100 #endif
  101 
  102 // Geometry optimization hack - Sometimes fails, so it is disabled...
  103 #define GEOMETRY_OPTIMIZATION 0
  104 
  105 // Private structures that allow to implement raise() and lower() methods
  106 
  107 #ifdef GTK3
  108 
  109 struct _GtkLayoutPrivate
  110 {
  111   /* Properties */
  112   guint width;
  113   guint height;
  114 
  115   GtkAdjustment *hadjustment;
  116   GtkAdjustment *vadjustment;
  117 
  118   /* GtkScrollablePolicy needs to be checked when
  119    * driving the scrollable adjustment values */
  120   guint hscroll_policy : 1;
  121   guint vscroll_policy : 1;
  122 
  123   /* Properties */
  124 
  125   GdkVisibilityState visibility;
  126   GdkWindow *bin_window;
  127 
  128   GList *children;
  129 
  130   gint scroll_x;
  131   gint scroll_y;
  132 
  133   guint freeze_count;
  134 };
  135 
  136 struct _GtkFixedPrivate
  137 {
  138   GList *children;
  139 };
  140 
  141 typedef struct _GtkLayoutChild GtkLayoutChild;
  142 
  143 struct _GtkLayoutChild {
  144   GtkWidget *widget;
  145   gint x;
  146   gint y;
  147 };
  148 
  149 #define GET_CHILDREN_LIST(_widget) 
  150 
  151 #else
  152 
  153 typedef struct _GtkLayoutChild   GtkLayoutChild;
  154 
  155 struct _GtkLayoutChild {
  156   GtkWidget *widget;
  157   gint x;
  158   gint y;
  159 };
  160 
  161 #endif
  162 
  163 
  164 #ifdef GTK3
  165 static gboolean cb_background_draw(GtkWidget *wid, cairo_t *cr, gControl *control)
  166 {
  167     control->drawBackground(cr);
  168     return false;
  169 }
  170 #else
  171 static gboolean cb_background_expose(GtkWidget *wid, GdkEventExpose *e, gControl *control)
  172 {
  173     control->drawBackground(e);
  174     return false;
  175 }
  176 #endif
  177 
  178 #ifdef GTK3
  179 static gboolean cb_frame_draw(GtkWidget *wid, cairo_t *cr, gControl *control)
  180 {
  181     control->drawBorder(cr);
  182     return false;
  183 }
  184 #else
  185 static gboolean cb_frame_expose(GtkWidget *wid, GdkEventExpose *e, gControl *control)
  186 {
  187     control->drawBorder(e);
  188     return false;
  189 }
  190 #endif
  191 
  192 #ifndef GTK3
  193 
  194 /****************************************************************************
  195 
  196 gPlugin
  197 
  198 ****************************************************************************/
  199 
  200 gboolean gPlugin_OnUnplug(GtkSocket *socket,gPlugin *data)
  201 {
  202     if (data->onUnplug) data->onUnplug(data);
  203     return true;
  204 }
  205 
  206 void gPlugin_OnPlug(GtkSocket *socket,gPlugin *data)
  207 {
  208     if (data->onPlug) data->onPlug(data);
  209 }
  210 
  211 
  212 gPlugin::gPlugin(gContainer *parent) : gControl(parent)
  213 {
  214     border = gtk_socket_new();
  215     widget = border;
  216     realize();
  217 
  218     onPlug = NULL;
  219     onUnplug = NULL;
  220 
  221     g_signal_connect(G_OBJECT(widget), "plug-removed", G_CALLBACK(gPlugin_OnUnplug), (gpointer)this);
  222     g_signal_connect(G_OBJECT(widget), "plug-added", G_CALLBACK(gPlugin_OnPlug), (gpointer)this);
  223 
  224     ON_DRAW_BEFORE(border, this, cb_background_expose, cb_background_draw);
  225 
  226     setCanFocus(true);
  227 }
  228 
  229 int gPlugin::client()
  230 {
  231     //GdkNativeWindow win = gtk_socket_get_id(GTK_SOCKET(widget));
  232     //return (long)win;
  233     GdkWindow *win = gtk_socket_get_plug_window(GTK_SOCKET(widget));
  234     if (!win)
  235         return 0;
  236     else
  237         return (int)GDK_WINDOW_XID(win);
  238 }
  239 
  240 void gPlugin::plug(int id)
  241 {
  242     void (*func)(gControl *);
  243     int i;
  244     Display *d = gdk_x11_display_get_xdisplay(gdk_display_get_default());
  245 
  246     func = onPlug;
  247     onPlug = NULL;
  248 
  249     for (i = 1; i >= 0; i--)
  250     {
  251         if (i == 0)
  252             onPlug = func;
  253 
  254         gtk_socket_add_id(GTK_SOCKET(widget), (Window)id);
  255     }
  256 
  257     if (client())
  258         XAddToSaveSet(d, client());
  259     else
  260         emit(SIGNAL(onError));
  261 }
  262 
  263 void gPlugin::discard()
  264 {
  265     #ifdef GDK_WINDOWING_X11
  266     if (MAIN_display_x11)
  267     {
  268         Display *d = gdk_x11_display_get_xdisplay(gdk_display_get_default());
  269 
  270         if (!client()) return;
  271 
  272         XRemoveFromSaveSet(d, client());
  273         XReparentWindow(d, client(), GDK_ROOT_WINDOW(), 0, 0);
  274     }
  275     #else
  276     stub("no-X11/gPlugin:discard()");
  277     #endif
  278 }
  279 #endif
  280 
  281 /*****************************************************************
  282 
  283 CREATION AND DESTRUCTION
  284 
  285 ******************************************************************/
  286 
  287 void gControl::postDelete()
  288 {
  289     GList *iter;
  290     gControl *control;
  291 
  292     gMenu::cleanRemovedMenus();
  293     
  294     if (!_destroy_list) return;
  295 
  296     for(;;)
  297     {
  298         iter = g_list_first(_destroy_list);
  299         if (!iter)
  300             break;
  301         control = (gControl *)iter->data;
  302 #if DEBUG_DESTROY
  303         fprintf(stderr, "postDelete: %p %s\n", control, control->name());
  304 #endif
  305         gtk_widget_destroy(control->border);
  306     }
  307 
  308     _destroy_list = NULL;
  309 }
  310 
  311 static bool always_can_raise(gControl *sender, int type)
  312 {
  313     return true;
  314 }
  315 
  316 void gControl::initAll(gContainer *parent)
  317 {
  318     bufW = 1;
  319     bufH = 1;
  320     bufX = -16;
  321     bufY = -16;
  322     
  323     _min_w = _min_h = 1;
  324     _minimum_size_set = FALSE;
  325     curs = NULL;
  326     _font = NULL;
  327     _resolved_font = NULL;
  328     _design = false;
  329     _design_ignore = false;
  330     _no_design = false;
  331     _expand = false;
  332     _ignore = false;
  333     _inverted = false;
  334     _accept_drops = false;
  335     _dragging = false;
  336     _drag_get_data = false;
  337     frame_border = 0;
  338     frame_padding = 0;
  339     _bg_set = false;
  340     _fg_set = false;
  341     have_cursor = false;
  342     use_base = false;
  343     _mouse = CURSOR_DEFAULT;
  344     pr = parent;
  345     _name = NULL;
  346     _visible = false;
  347     _locked = 0;
  348     _destroyed = false;
  349     _no_delete = false;
  350     _action = false;
  351     _dirty_pos = _dirty_size = false;
  352     _tracking = false;
  353     _has_input_method = false;
  354     _no_default_mouse_event = false;
  355     _proxy = _proxy_for = NULL;
  356     _no_tab_focus = false;
  357     _inside = false;
  358     _no_auto_grab = false;
  359     _no_background = false;
  360     _use_wheel = false;
  361     _scrollbar = SCROLL_NONE;
  362     _input_method = NULL;
  363     _tooltip = NULL;
  364     _is_container = false;
  365     _is_window = false;
  366     _is_button = false;
  367     _is_drawingarea = false;
  368     _has_native_popup = false;
  369     _eat_return_key = false;
  370     _hidden_temp = false;
  371     _allow_show = false;
  372 
  373     onFinish = NULL;
  374     onFocusEvent = NULL;
  375     onKeyEvent = NULL;
  376     onMouseEvent = NULL;
  377     onDrag = NULL;
  378     onDragMove = NULL;
  379     onDrop = NULL;
  380     onDragLeave = NULL;
  381     onEnterLeave = NULL;
  382     canRaise = always_can_raise;
  383 
  384     frame = border = widget = NULL;
  385     _scroll = NULL;
  386     hFree = NULL;
  387     _grab = false;
  388 
  389     _fg = _bg = COLOR_DEFAULT;
  390 #ifdef GTK3
  391     _css = NULL;
  392     _has_css_id = false;
  393     _style_dirty = false;
  394     _no_style_without_child = false;
  395 #endif
  396 }
  397 
  398 gControl::gControl()
  399 {
  400     initAll(NULL);
  401 }
  402 
  403 gControl::gControl(gContainer *parent)
  404 {
  405     initAll(parent);
  406 }
  407 
  408 void gControl::dispose()
  409 {
  410     gMainWindow *win;
  411     
  412     win = window();
  413     if (win && win->focus == this)
  414         win->focus = NULL;
  415 
  416     if (pr)
  417     {
  418         pr->remove(this);
  419         pr = NULL;
  420     }
  421 }
  422 
  423 gControl::~gControl()
  424 {
  425     //fprintf(stderr, "~gControl: %s %p %s\n", name(), this, GB.GetClassName(hFree));
  426     emit(SIGNAL(onFinish));
  427 
  428     dispose();
  429 
  430     if (_proxy)
  431         _proxy->_proxy_for = NULL;
  432     if (_proxy_for)
  433         _proxy_for->_proxy = NULL;
  434 
  435     if (gDrag::getSource() == this)
  436         gDrag::cancel();
  437 
  438     if (curs)
  439     {
  440         delete curs;
  441         curs=NULL;
  442     }
  443 
  444     if (_font)
  445     {
  446         gFont::assign(&_font);
  447         gFont::assign(&_resolved_font);
  448     }
  449 
  450 #ifdef GTK3
  451     if (_css)
  452         g_object_unref(_css);
  453 #endif
  454 
  455     if (_name)
  456         g_free(_name);
  457     if (_tooltip)
  458         g_free(_tooltip);
  459 
  460 #if DEBUG_DESTROY
  461     fprintf(stderr, "remove from destroy list: %p (%d)\n", this, _destroyed);
  462 #endif
  463     _destroy_list = g_list_remove(_destroy_list, this);
  464 
  465     #define CLEAN_POINTER(_p) if (_p == this) _p = NULL
  466 
  467     CLEAN_POINTER(gApplication::_enter);
  468     CLEAN_POINTER(gApplication::_leave);
  469     CLEAN_POINTER(gApplication::_active_control);
  470     CLEAN_POINTER(gApplication::_previous_control);
  471     CLEAN_POINTER(gApplication::_old_active_control);
  472     CLEAN_POINTER(gApplication::_button_grab);
  473     CLEAN_POINTER(gApplication::_enter_after_button_grab);
  474     CLEAN_POINTER(gApplication::_control_grab);
  475     CLEAN_POINTER(gApplication::_ignore_until_next_enter);
  476     CLEAN_POINTER(gDrag::_destination);
  477     CLEAN_POINTER(gDrag::_source);
  478     CLEAN_POINTER(gDrag::_current);
  479     CLEAN_POINTER(gMouse::_control);
  480 }
  481 
  482 void gControl::destroy()
  483 {
  484     if (_destroyed)
  485         return;
  486 
  487 #if DEBUG_DESTROY
  488     fprintf(stderr, "destroy: %p %s (%d)\n", this, name(), _destroyed);
  489 #endif
  490     hide();
  491     _destroyed = true;
  492     dispose();
  493 
  494 #if DEBUG_DESTROY
  495     fprintf(stderr, "added to destroy list: %p %s (%d)\n", this, name(), _destroyed);
  496     if (g_list_find(_destroy_list, this))
  497     {
  498         fprintf(stderr, "already present!!!\n");
  499         BREAKPOINT();
  500     }
  501 #endif
  502 
  503     _destroy_list = g_list_prepend(_destroy_list, (gpointer)this);
  504 }
  505 
  506 
  507 bool gControl::isEnabled() const
  508 {
  509     return gtk_widget_is_sensitive(border);
  510 }
  511 
  512 bool gControl::isReallyVisible()
  513 {
  514     if (!isTopLevel() && !topLevel()->isReallyVisible())
  515         return false;
  516 
  517 #if GTK_CHECK_VERSION(2, 20, 0)
  518     return gtk_widget_get_mapped(border);
  519 #else
  520     return GTK_WIDGET_MAPPED(border);
  521 #endif
  522 }
  523 
  524 void gControl::setEnabled(bool vl)
  525 {
  526     gtk_widget_set_sensitive(border, vl);
  527 }
  528 
  529 void gControl::setVisibility(bool vl)
  530 {
  531     _visible = vl;
  532     
  533     if (!_allow_show)
  534         return;
  535 
  536     if (vl == gtk_widget_get_visible(border))
  537         return;
  538 
  539     if (vl)
  540     {
  541         if (bufW >= minimumWidth() && bufH >= minimumHeight())
  542         {
  543             gtk_widget_show(border);
  544             _dirty_size = true;
  545             updateGeometry();
  546     #ifdef GTK3
  547             updateStyleSheet(false);
  548     #endif
  549         }
  550     }
  551     else
  552     {
  553         if (parent() && hasFocus())
  554             gcb_focus(widget, GTK_DIR_TAB_FORWARD, this);
  555         if (gtk_widget_has_grab(border))
  556             gtk_grab_remove(border);
  557         gtk_widget_hide(border);
  558     }
  559 
  560     if (!isIgnore() && pr) pr->performArrange();
  561 }
  562 
  563 void gControl::setVisible(bool vl)
  564 {
  565     setVisibility(vl);
  566     checkVisibility();
  567 }
  568 
  569 /*****************************************************************
  570 
  571 POSITION AND SIZE
  572 
  573 ******************************************************************/
  574 
  575 bool gControl::getScreenPos(int *x, int *y)
  576 {
  577     if (!gtk_widget_get_window(border))
  578     {
  579         if (pr)
  580         {
  581             pr->getScreenPos(x, y);
  582             x += pr->clientX() + bufX;
  583             y += pr->clientY() + bufY;
  584             return false;
  585         }
  586         
  587         *x = *y = 0; // widget is not realized
  588         return true;
  589     }
  590 
  591     gdk_window_get_origin(gtk_widget_get_window(border), x, y);
  592 
  593     //fprintf(stderr, "getScreenPos: %s: %d %d: %d\n", name(), *x, *y, gtk_widget_get_has_window(border));
  594 
  595     #if GTK_CHECK_VERSION(2, 18, 0)
  596     if (!gtk_widget_get_has_window(border))
  597     {
  598         GtkAllocation a;
  599         gtk_widget_get_allocation(border, &a);
  600         *x += a.x;
  601         *y += a.y;
  602     }
  603     #endif
  604 
  605     //fprintf(stderr, "getScreenPos: --> %d %d\n", *x, *y);
  606     return false;
  607 }
  608 
  609 int gControl::screenX()
  610 {
  611     if (isTopLevel())
  612     {
  613         GdkWindow *window = gtk_widget_get_window(border);
  614         int x = 0;
  615         GtkAllocation a;
  616         
  617         if (window)
  618             gdk_window_get_origin(window, &x, NULL);
  619         
  620         gtk_widget_get_allocation(widget, &a);
  621         
  622         return x + a.x - ((gContainer *)this)->clientX();
  623     }
  624     
  625     return pr->screenX() + x() - pr->clientX() - pr->scrollX();
  626 }
  627 
  628 int gControl::screenY()
  629 {
  630     if (isTopLevel())
  631     {
  632         GdkWindow *window = gtk_widget_get_window(border);
  633         int y = 0;
  634         GtkAllocation a;
  635         
  636         if (window)
  637             gdk_window_get_origin(window, NULL, &y);
  638         
  639         gtk_widget_get_allocation(widget, &a);
  640         
  641         return y + a.y - ((gContainer *)this)->clientY();
  642     }
  643     
  644     return pr->screenY() + y() + pr->clientY() - pr->scrollY();
  645 }
  646 
  647 static void send_configure (gControl *control)
  648 {
  649     GtkWidget *widget;
  650     GdkEvent *event;
  651 
  652     widget = control->border;
  653 
  654 #if GTK_CHECK_VERSION(2, 20, 0)
  655     if (!gtk_widget_get_realized(widget))
  656         return;
  657 #else
  658     if (!GTK_WIDGET_REALIZED(widget))
  659         return;
  660 #endif
  661 
  662 //  if (control->isWindow())
  663 //   g_debug("send configure to window: %s", control->name());
  664 
  665     event = gdk_event_new(GDK_CONFIGURE);
  666 
  667     event->configure.window = NULL; //(GdkWindow *)g_object_ref(widget->window);
  668     event->configure.send_event = TRUE;
  669     event->configure.x = control->x();
  670     event->configure.y = control->y();
  671     event->configure.width = control->width();
  672     event->configure.height = control->height();
  673 
  674     gtk_widget_event(widget, event);
  675     gdk_event_free(event);
  676 }
  677 
  678 void gControl::move(int x, int y)
  679 {
  680     //GtkLayout *fx;
  681 
  682     if (x == bufX && y == bufY)
  683         return;
  684 
  685     bufX = x;
  686     bufY = y;
  687 
  688     //g_debug("move: %p: %d %d", this, x, y);
  689     _dirty_pos = true;
  690     if (pr && !isIgnore())
  691     {
  692         // TODO: check the following optimization to see if it can be enabled again
  693         //if (gtk_widget_get_parent(border) == pr->getContainer())
  694             pr->performArrange();
  695     }
  696 
  697     #if GEOMETRY_OPTIMIZATION
  698     gApplication::setDirty();
  699     #else
  700     updateGeometry();
  701     #endif
  702     
  703     /*if (name() && !::strcmp(name(), "txtTagEditor") && y == 43)
  704         BREAKPOINT();*/
  705 
  706     checkVisibility();
  707     
  708     send_configure(this); // needed for Watcher and Form Move events
  709 }
  710 
  711 void gControl::hideButKeepFocus()
  712 {
  713     //fprintf(stderr, "gControl::hideButKeepFocus: %s\n", gApplication::_active_control ? gApplication::_active_control->name() : "NULL");
  714 
  715     _hidden_temp = true;
  716     gApplication::_keep_focus = true;
  717     gtk_widget_hide(border);
  718     gApplication::_keep_focus = false;
  719 }
  720 
  721 void gControl::showButKeepFocus()
  722 {
  723     gControl *focus;
  724 
  725     //fprintf(stderr, "gControl::showButKeepFocus: %s\n", gApplication::_active_control ? gApplication::_active_control->name() : "NULL");
  726 
  727     if (_allow_show)
  728         gtk_widget_show(border);
  729     
  730     focus = gApplication::_active_control;
  731     if (focus)
  732     {
  733         gApplication::_active_control = NULL;
  734         if (!focus->hasFocus())
  735             focus->setFocus();
  736         gApplication::_active_control = focus;
  737     }
  738 
  739     _hidden_temp = false;
  740 }
  741 
  742 bool gControl::resize(int w, int h, bool no_decide)
  743 {
  744     bool decide_w, decide_h;
  745     
  746     if (w < 0 && h < 0)
  747         return true;
  748     
  749     if (pr && !no_decide)
  750     {
  751         pr->decide(this, &decide_w, &decide_h);
  752 
  753         if (w < 0 || decide_w)
  754             w = width();
  755 
  756         if (h < 0 || decide_h)
  757             h = height();
  758     }
  759 
  760     if (w <= 0) w = 1;
  761     if (h <= 0) h = 1;
  762 
  763     if (width() == w && height() == h)
  764         return true;
  765     
  766     bufW = w;
  767     bufH = h;
  768     
  769     if (w < minimumWidth() || h < minimumHeight())
  770     {
  771         hideButKeepFocus();
  772     }
  773     else
  774     {
  775         /*if (frame && widget != border)
  776         {
  777             int fw = getFrameWidth() * 2;
  778             if (w < fw || h < fw)
  779                 gtk_widget_hide(widget);
  780             else
  781                 gtk_widget_show(widget);
  782         }*/
  783 
  784         //g_debug("resize: %p %s: %d %d", this, name(), w, h);
  785         _dirty_size = true;
  786 
  787         #if GEOMETRY_OPTIMIZATION
  788         gApplication::setDirty();
  789         #else
  790         updateGeometry();
  791         #endif
  792         
  793         if (isVisible() && !isReallyVisible())
  794         {
  795             showButKeepFocus();
  796 #ifdef GTK3
  797             updateStyleSheet(false);
  798 #endif
  799         }
  800     }
  801 
  802     checkVisibility();
  803     
  804     if (pr && !isIgnore())
  805         pr->performArrange();
  806 
  807     send_configure(this); // needed for Watcher and Form Resize events
  808     return false;
  809 }
  810 
  811 void gControl::moveResize(int x, int y, int w, int h, bool no_decide)
  812 {
  813     if (pr)
  814         pr->disableArrangement();
  815 
  816     move(x, y);
  817     resize(w, h, no_decide);
  818 
  819     if (pr)
  820         pr->enableArrangement();
  821 }
  822 
  823 void gControl::updateGeometry(bool force)
  824 {
  825 //  if (_dirty_pos)
  826 //  {
  827 //      g_debug("move: %p -> %d %d", this, x(), y());
  828 //      _dirty_pos = false;
  829 //      GtkLayout *fx = GTK_LAYOUT(gtk_widget_get_parent(border));
  830 //      gtk_layout_move(fx, border, x(), y());
  831 //  }
  832 //
  833 //  if (_dirty_size)
  834 //  {
  835 //      GtkAllocation a = { x(), y(), width(), height() };
  836 //      g_debug("resize: %p -> %d %d", this, width(), height());
  837 //      _dirty_size = false;
  838 //      //gtk_widget_set_size_request(border, width(), height());
  839 //      gtk_widget_size_allocate(border,
  840 //  }
  841     if (force || _dirty_pos || _dirty_size)
  842     {
  843         //g_debug("move-resize: %s: %d %d %d %d", this->name(), x(), y(), width(), height());
  844         if (force || _dirty_pos)
  845         {
  846             if (pr)
  847                 pr->moveChild(this, x(), y());
  848 
  849             _dirty_pos = false;
  850         }
  851         if ((force || _dirty_size) && isVisible())
  852         {
  853             gtk_widget_set_size_request(border, width(), height());
  854             _dirty_size = false;
  855         }
  856     }
  857 }
  858 
  859 /*****************************************************************
  860 
  861 APPEARANCE
  862 
  863 ******************************************************************/
  864 
  865 
  866 void gControl::setExpand(bool vl)
  867 {
  868     if (vl == _expand)
  869         return;
  870 
  871     _expand = vl;
  872     checkVisibility();
  873 
  874     if (pr && !_ignore)
  875         pr->performArrange();
  876 }
  877 
  878 void gControl::setIgnore(bool vl)
  879 {
  880     if (vl == _ignore)
  881         return;
  882 
  883     _ignore = vl;
  884     if (pr)
  885         pr->performArrange();
  886 }
  887 
  888 void gControl::setTooltip(char *vl)
  889 {
  890     char *pango;
  891 
  892     if (_tooltip) g_free(_tooltip);
  893     _tooltip = NULL;
  894     if (vl && *vl) _tooltip = g_strdup(vl);
  895 
  896     if (_tooltip)
  897     {
  898         pango = gt_html_to_pango_string(_tooltip, -1, true);
  899         gtk_widget_set_tooltip_markup(border, pango);
  900         g_free(pango);
  901     }
  902     else
  903         gtk_widget_set_tooltip_markup(border, NULL);
  904 }
  905 
  906 gFont* gControl::font() const
  907 {
  908     if (_resolved_font)
  909     {
  910         //fprintf(stderr, "%s: font -> _resolved_font\n", name());
  911         return _resolved_font;
  912     }
  913     else if (pr)
  914     {
  915         //fprintf(stderr, "%s: font -> parent\n", name());
  916         return pr->font();
  917     }
  918     else
  919     {
  920         //fprintf(stderr, "%s: font -> desktop\n", name());
  921         return gDesktop::font();
  922     }
  923 }
  924 
  925 void gControl::actualFontTo(gFont *ft)
  926 {
  927     font()->copyTo(ft);
  928 }
  929 
  930 void gControl::resolveFont()
  931 {
  932     gFont *font;
  933 
  934     if (_font)
  935     {
  936         font = new gFont();
  937         font->mergeFrom(_font);
  938         if (pr)
  939             font->mergeFrom(pr->font());
  940         else
  941             font->mergeFrom(gDesktop::font());
  942 
  943         gFont::set(&_resolved_font, font);
  944     }
  945     else
  946         gFont::assign(&_resolved_font);
  947 }
  948 
  949 void gControl::setFont(gFont *ft)
  950 {
  951     //fprintf(stderr, "setFont: %s: %s\n", name(), ft->toFullString());
  952     if (ft)
  953         gFont::assign(&_font, ft);
  954     else if (_font)
  955         gFont::assign(&_font);
  956 
  957     gFont::assign(&_resolved_font);
  958 
  959     updateFont();
  960 
  961     resize();
  962 
  963     //fprintf(stderr, "--> %s: _font = %s\n", name(), _font ? _font->toFullString() : NULL);
  964 }
  965 
  966 #ifdef GTK3
  967 
  968 void gControl::updateFont()
  969 {
  970     resolveFont();
  971     updateStyleSheet(true);
  972     updateSize();
  973 }
  974 
  975 #else
  976 
  977 static void cb_update_font(GtkWidget *widget, gpointer data)
  978 {
  979     PangoFontDescription *desc = (PangoFontDescription *)data;
  980     gtk_widget_modify_font(widget, desc);
  981 }
  982 
  983 void gControl::updateFont()
  984 {
  985     resolveFont();
  986     gtk_widget_modify_font(widget, font()->desc());
  987     if (!isContainer() && GTK_IS_CONTAINER(widget))
  988         gtk_container_forall(GTK_CONTAINER(widget), (GtkCallback)cb_update_font, (gpointer)font()->desc());
  989     refresh();
  990     updateSize();
  991 }
  992 
  993 #endif
  994 
  995 void gControl::updateSize()
  996 {
  997 }
  998 
  999 int gControl::mouse()
 1000 {
 1001     if (_proxy)
 1002         return _proxy->mouse();
 1003     else
 1004         return _mouse;
 1005 }
 1006 
 1007 gCursor* gControl::cursor()
 1008 {
 1009     if (_proxy)
 1010         return _proxy->cursor();
 1011 
 1012     if (!curs) return NULL;
 1013     return new gCursor(curs);
 1014 }
 1015 
 1016 void gControl::setCursor(gCursor *vl)
 1017 {
 1018     if (_proxy)
 1019     {
 1020         _proxy->setCursor(vl);
 1021         return;
 1022     }
 1023 
 1024     if (curs) { delete curs; curs=NULL;}
 1025     if (!vl)
 1026     {
 1027         setMouse(CURSOR_DEFAULT);
 1028         return;
 1029     }
 1030     curs=new gCursor(vl);
 1031     setMouse(CURSOR_CUSTOM);
 1032 }
 1033 
 1034 void gControl::updateCursor(GdkCursor *cursor)
 1035 {
 1036     if (GDK_IS_WINDOW(gtk_widget_get_window(border)) && _inside)
 1037     {
 1038         if (cursor || isWindow())
 1039             gdk_window_set_cursor(gtk_widget_get_window(border), cursor);
 1040         
 1041         if (!cursor && parent())
 1042             parent()->updateCursor(parent()->getGdkCursor());
 1043     }
 1044 }
 1045 
 1046 GdkCursor *gControl::getGdkCursor()
 1047 {
 1048     const char *name;
 1049     GdkCursor *cr = NULL;
 1050     int m = _mouse;
 1051 
 1052     if (gApplication::isBusy())
 1053         m = GDK_WATCH;
 1054 
 1055     if (m == CURSOR_CUSTOM)
 1056     {
 1057         if (curs && curs->cur)
 1058             return curs->cur;
 1059     }
 1060 
 1061     if (m != CURSOR_DEFAULT)
 1062     {
 1063         switch(m)
 1064         {
 1065             case GDK_BLANK_CURSOR: name = "none"; break;
 1066             case GDK_LEFT_PTR: name = "default"; break;
 1067             case GDK_CROSSHAIR: name = "crosshair"; break;
 1068             case GDK_WATCH: name = "wait"; break;
 1069             case GDK_XTERM: name = "text"; break;
 1070             case GDK_FLEUR: name = "move"; break;
 1071             case GDK_SB_H_DOUBLE_ARROW: name = "ew-resize"; break;
 1072             case GDK_SB_V_DOUBLE_ARROW: name = "ns-resize"; break;
 1073             case GDK_TOP_SIDE: name = "n-resize"; break;
 1074             case GDK_BOTTOM_SIDE: name = "s-resize"; break;
 1075             case GDK_LEFT_SIDE: name = "w-resize"; break;
 1076             case GDK_RIGHT_SIDE: name = "e-resize"; break;
 1077             case GDK_TOP_LEFT_CORNER: name = "nw-resize"; break;
 1078             case GDK_BOTTOM_RIGHT_CORNER: name = "se-resize"; break;
 1079             case GDK_TOP_RIGHT_CORNER: name = "ne-resize"; break;
 1080             case GDK_BOTTOM_LEFT_CORNER: name = "sw-resize"; break;
 1081             case GDK_LAST_CURSOR+1: name = "nwse-resize"; break;
 1082             case GDK_LAST_CURSOR+2: name = "nesw-resize"; break;
 1083             case GDK_HAND2: name = "pointer"; break;
 1084             default: name = "default";
 1085         }
 1086 
 1087         cr = gdk_cursor_new_from_name(gdk_display_get_default(), name);
 1088         if (!cr)
 1089             cr = gdk_cursor_new_for_display(gdk_display_get_default(), (GdkCursorType)m);
 1090 
 1091         /*
 1092         if (m < GDK_LAST_CURSOR)
 1093         {
 1094             cr = gdk_cursor_new_for_display(gdk_display_get_default(), (GdkCursorType)m);
 1095         }
 1096         else
 1097         {
 1098             if (m == (GDK_LAST_CURSOR+1)) //FDiag
 1099             {
 1100                 pix = gdk_pixbuf_new_from_xpm_data(_cursor_fdiag);
 1101                 cr = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pix, 8, 8);
 1102                 g_object_unref(pix);
 1103             }
 1104             else if (m == (GDK_LAST_CURSOR+2)) //BDiag
 1105             {
 1106                 pix = gdk_pixbuf_new_from_xpm_data(_cursor_bdiag);
 1107                 cr = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pix, 8, 8);
 1108                 g_object_unref(pix);
 1109             }
 1110         }*/
 1111     }
 1112 
 1113     return cr;
 1114 }
 1115 
 1116 void gControl::setMouse(int m)
 1117 {
 1118     if (_proxy)
 1119     {
 1120         _proxy->setMouse(m);
 1121         return;
 1122     }
 1123 
 1124     if (m == CURSOR_CUSTOM)
 1125     {
 1126         if (!curs || !curs->cur)
 1127             m = CURSOR_DEFAULT;
 1128     }
 1129 
 1130     _mouse = m;
 1131 
 1132     updateCursor(getGdkCursor());
 1133 }
 1134 
 1135 
 1136 
 1137 /*****************************************************************
 1138 
 1139 HANDLES
 1140 
 1141 ******************************************************************/
 1142 
 1143 gMainWindow* gControl::window() const
 1144 {
 1145     if (isWindow())
 1146         return (gMainWindow *)this;
 1147 
 1148     if (!pr)
 1149         return NULL;
 1150     else
 1151         return pr->window();
 1152 }
 1153 
 1154 gMainWindow* gControl::topLevel() const
 1155 {
 1156     const gControl *child = this;
 1157 
 1158     while (!child->isTopLevel())
 1159         child = child->parent();
 1160 
 1161     return (gMainWindow *)child;
 1162 }
 1163 
 1164 long gControl::handle()
 1165 {
 1166 #ifdef GTK3
 1167     GdkWindow *window = gtk_widget_get_window(border);
 1168     return PLATFORM.Window.GetId(window);
 1169 #else
 1170     if (MAIN_display_x11)
 1171     {
 1172         GdkWindow *window = gtk_widget_get_window(border);
 1173         return window ? GDK_WINDOW_XID(window) : 0;
 1174     }
 1175     else
 1176         return 0;
 1177 #endif
 1178 }
 1179 
 1180 /*****************************************************************
 1181 
 1182 MISC
 1183 
 1184 ******************************************************************/
 1185 
 1186 void gControl::refresh()
 1187 {
 1188     gtk_widget_queue_draw(border);
 1189     if (frame != border && GTK_IS_WIDGET(frame))
 1190         gtk_widget_queue_draw(frame);
 1191     if (widget != frame  && GTK_IS_WIDGET(widget))
 1192         gtk_widget_queue_draw(widget);
 1193 
 1194     afterRefresh();
 1195 }
 1196 
 1197 void gControl::refresh(int x, int y, int w, int h)
 1198 {
 1199     GtkAllocation a;
 1200     /*GdkRectangle r;
 1201     GtkAllocation a;*/
 1202 
 1203     //gtk_widget_get_allocation(border, &a);
 1204 
 1205     if (x < 0 || y < 0 || w <= 0 || h <= 0)
 1206     {
 1207         x = y = 0;
 1208         w = width();
 1209         h = height();
 1210     }
 1211     
 1212     if (w <= 0 || h <= 0)
 1213         return;
 1214 
 1215     gtk_widget_get_allocation(widget, &a);
 1216     
 1217     gtk_widget_queue_draw_area(widget, x + a.x, y + a.y, w, h);
 1218     
 1219     afterRefresh();
 1220 }
 1221 
 1222 void gControl::afterRefresh()
 1223 {
 1224 }
 1225 
 1226 void gControl::setDesign(bool ignore)
 1227 {
 1228     if (_design)
 1229         return;
 1230     
 1231     //fprintf(stderr, "setDesign: %s %d\n", name(), ignore);
 1232     setCanFocus(false);
 1233     setMouse(GDK_LEFT_PTR);
 1234     setTooltip(NULL);
 1235     _design = true;
 1236     _design_ignore = ignore;
 1237 }
 1238 
 1239 void gControl::updateDesign()
 1240 {
 1241     if (!_design)
 1242         return;
 1243     
 1244     _design = false;
 1245     setDesign(_design_ignore);
 1246 }
 1247 
 1248 gControl *gControl::ignoreDesign()
 1249 {
 1250     //fprintf(stderr, "ignoreDesign: %s", name());
 1251     
 1252     if (!isDesignIgnore())
 1253         return this;
 1254     
 1255     gControl *ctrl = this;
 1256     while (ctrl && ctrl->isDesignIgnore())
 1257         ctrl = ctrl->parent();
 1258 
 1259     //fprintf(stderr, " --> %s\n", ctrl->name());
 1260     return ctrl;
 1261 }
 1262 
 1263 bool gControl::canFocus() const
 1264 {
 1265     #if DEBUG_FOCUS
 1266     fprintf(stderr, "canFocus: %s ?\n", name());
 1267     #endif
 1268     /*if (_proxy)
 1269         return _proxy->canFocus();*/
 1270     
 1271     #if DEBUG_FOCUS
 1272     fprintf(stderr, "canFocus: %s -> %d\n", name(), gtk_widget_get_can_focus(widget));
 1273     #endif
 1274     
 1275 #if GTK_CHECK_VERSION(2, 18, 0)
 1276     return gtk_widget_get_can_focus(widget);
 1277 #else
 1278     return GTK_WIDGET_CAN_FOCUS(widget);
 1279 #endif
 1280 }
 1281 
 1282 bool gControl::canFocusOnClick() const
 1283 {
 1284     /*if (_proxy)
 1285         return _proxy->canFocusOnClick();*/
 1286     if (isWindow())
 1287         return false;
 1288     if (!GTK_IS_BUTTON(widget))
 1289         return true;
 1290     return gt_get_focus_on_click(widget);
 1291 }
 1292 
 1293 void gControl::setCanFocus(bool vl)
 1294 {
 1295     #if DEBUG_FOCUS
 1296     fprintf(stderr, "setCanFocus: %s %d ?\n", name(), vl);
 1297     #endif
 1298     if (isDesign() || vl == canFocus())
 1299         return;
 1300 
 1301     /*if (_proxy)
 1302         _proxy->setCanFocus(vl);
 1303     else*/
 1304     {
 1305         #if DEBUG_FOCUS
 1306         fprintf(stderr, "setCanFocus: %s %p %d\n", name(), this, vl);
 1307         #endif
 1308         gtk_widget_set_can_focus(widget, vl);
 1309     }
 1310 
 1311     /*_has_input_method = vl;
 1312 
 1313     if (_input_method && !vl)
 1314     {
 1315         g_object_unref(_input_method);
 1316         _input_method = NULL;
 1317     }
 1318     else if (!_input_method && vl)
 1319     {
 1320         _input_method = gtk_im_multicontext_new();
 1321     }*/
 1322 
 1323 }
 1324 
 1325 void gControl::setFocus()
 1326 {
 1327     #if DEBUG_FOCUS
 1328     fprintf(stderr, "setFocus %s ?\n", name());
 1329     #endif
 1330     
 1331     if (_proxy)
 1332     {
 1333         _proxy->setFocus();
 1334         return;
 1335     }
 1336 
 1337     if (hasFocus())
 1338         return;
 1339     
 1340     gMainWindow *win = window();
 1341 
 1342     if (!win)
 1343         return;
 1344 
 1345     if (win->isVisible())
 1346     {
 1347         //if (isVisible() && bufW > 0 && bufH > 0)
 1348         #if DEBUG_FOCUS
 1349         fprintf(stderr, "setFocus now %s\n", name());
 1350         #endif
 1351         //win->activate();
 1352         
 1353         gtk_widget_grab_focus(widget);
 1354     }
 1355     else
 1356     {
 1357         #if DEBUG_FOCUS
 1358         fprintf(stderr, "setFocus later %s\n", name());
 1359         #endif
 1360         win->focus = this;
 1361     }
 1362 }
 1363 
 1364 bool gControl::hasFocus() const
 1365 {
 1366     if (_proxy)
 1367         return _proxy->hasFocus();
 1368     else
 1369 #if GTK_CHECK_VERSION(2, 18, 0)
 1370         return (border && gtk_widget_has_focus(border)) || (widget && gtk_widget_has_focus(widget)) || gApplication::activeControl() == this;
 1371 #else
 1372         return (border && GTK_WIDGET_HAS_FOCUS(border)) || (widget && GTK_WIDGET_HAS_FOCUS(widget)) || gApplication::activeControl() == this;
 1373 #endif
 1374 }
 1375 
 1376 #if GTK_CHECK_VERSION(3, 2, 0)
 1377 bool gControl::hasVisibleFocus() const
 1378 {
 1379     if (_proxy)
 1380         return _proxy->hasVisibleFocus();
 1381     else
 1382         return (border && gtk_widget_has_visible_focus(border)) || (widget && gtk_widget_has_visible_focus(widget));
 1383 }
 1384 #endif
 1385 
 1386 gControl* gControl::next()
 1387 {
 1388     int index;
 1389 
 1390     if (!pr)
 1391         return NULL;
 1392 
 1393     index = pr->childIndex(this);
 1394     if (index < 0 || index >= pr->childCount())
 1395         return NULL;
 1396     else
 1397         return pr->child(index + 1);
 1398 }
 1399 
 1400 gControl* gControl::previous()
 1401 {
 1402     int index;
 1403 
 1404     if (!pr)
 1405         return NULL;
 1406 
 1407     index = pr->childIndex(this);
 1408     if (index <= 0)
 1409         return NULL;
 1410     else
 1411         return pr->child(index - 1);
 1412 }
 1413 
 1414 static int find_child_fixed(GtkFixedChild *data, GtkWidget *widget)
 1415 {
 1416     return !(data->widget == widget);
 1417 }
 1418     
 1419 static int find_child_layout(GtkLayoutChild *data, GtkWidget *widget)
 1420 {
 1421     return !(data->widget == widget);
 1422 }
 1423 
 1424 static GList **get_children_list(GtkContainer *parent)
 1425 {
 1426 #ifdef GTK3
 1427     if (GTK_IS_LAYOUT(parent))
 1428         return &((GtkLayout *)parent)->priv->children;
 1429     else
 1430         return &((GtkFixed *)parent)->priv->children;
 1431 #else
 1432     if (GTK_IS_LAYOUT(parent))
 1433         return &((GtkLayout *)parent)->children;
 1434     else
 1435         return &((GtkFixed *)parent)->children;
 1436 #endif
 1437 }
 1438 
 1439 void gControl::restack(bool raise)
 1440 {
 1441     GtkContainer *parent;
 1442     GList **children;
 1443     GList *find;
 1444     gpointer *p;
 1445 
 1446     if (!pr) 
 1447         return;
 1448 
 1449     parent = GTK_CONTAINER(gtk_widget_get_parent(border));
 1450     
 1451     //fprintf(stderr, "%s: %s -> %s (%s%s)\n", raise ? "raise" : "lower", name(), pr->name(), GTK_IS_LAYOUT(parent) ? "L" : "F", gtk_widget_get_has_window(border) ? "W" : "");
 1452     
 1453     children = get_children_list(parent);
 1454     
 1455     if (GTK_IS_LAYOUT(parent))
 1456         find = g_list_find_custom(*children, border, (GCompareFunc)find_child_layout);
 1457     else if (GTK_IS_FIXED(parent))
 1458         find = g_list_find_custom(*children, border, (GCompareFunc)find_child_fixed);
 1459     else
 1460         return;
 1461     
 1462     if (_visible)
 1463         hideButKeepFocus();
 1464     
 1465     *children = g_list_remove_link(*children, find);
 1466     if (raise)
 1467         *children = g_list_concat(*children, find);
 1468     else
 1469         *children = g_list_concat(find, *children);
 1470     
 1471     if (gtk_widget_get_has_window(border))
 1472     {
 1473         if (raise)
 1474             gdk_window_raise(gtk_widget_get_window(border));
 1475         else
 1476             gdk_window_lower(gtk_widget_get_window(border));
 1477     }
 1478     
 1479     g_ptr_array_remove(pr->_children, this);
 1480     
 1481     if (raise)
 1482     {
 1483         g_ptr_array_add(pr->_children, this);
 1484     }
 1485     else
 1486     {
 1487         g_ptr_array_add(pr->_children, NULL);
 1488         p = pr->_children->pdata;
 1489         memmove(&p[1], &p[0], (pr->_children->len - 1) * sizeof(gpointer));
 1490         p[0] = this;
 1491     }
 1492     
 1493     if (_visible)
 1494         showButKeepFocus();
 1495 
 1496     updateGeometry(true);
 1497     pr->performArrange();
 1498     pr->refresh();
 1499 }
 1500 
 1501 void gControl::setNext(gControl *ctrl)
 1502 {
 1503     GPtrArray *ch;
 1504     uint i;
 1505 
 1506     if (!ctrl)
 1507     {
 1508         raise();
 1509         return;
 1510     }
 1511 
 1512     if (ctrl == this || isTopLevel() || ctrl->parent() != parent())
 1513         return;
 1514 
 1515     if (gtk_widget_get_has_window(ctrl->border) && gtk_widget_get_has_window(border))
 1516         gdk_window_restack(gtk_widget_get_window(border), gtk_widget_get_window(ctrl->border), FALSE);
 1517 
 1518     ch = pr->_children;
 1519     g_ptr_array_remove(ch, this);
 1520     g_ptr_array_add(ch, NULL);
 1521 
 1522     for (i = 0; i < ch->len; i++)
 1523     {
 1524         if (g_ptr_array_index(ch, i) == ctrl)
 1525         {
 1526             memmove(&ch->pdata[i + 1], &ch->pdata[i], (ch->len - i - 1) * sizeof(gpointer));
 1527             ch->pdata[i] = this;
 1528             break;
 1529         }
 1530     }
 1531 
 1532     pr->performArrange();
 1533 }
 1534 
 1535 void gControl::setPrevious(gControl *ctrl)
 1536 {
 1537     if (!ctrl)
 1538         lower();
 1539     else
 1540         setNext(ctrl->next());
 1541 }
 1542 
 1543 /*********************************************************************
 1544 
 1545 Drag & Drop
 1546 
 1547 **********************************************************************/
 1548 
 1549 void gControl::setAcceptDrops(bool vl)
 1550 {
 1551     //GtkWidget *w;
 1552     //GtkTargetEntry entry[7];
 1553 
 1554     /* BM: ??
 1555     if (!pr) w=frame;
 1556     else w=widget;
 1557     */
 1558 
 1559     if (vl == _accept_drops)
 1560         return;
 1561 
 1562     _accept_drops = vl;
 1563 
 1564     if (vl)
 1565     {
 1566         gtk_drag_dest_set(border, (GtkDestDefaults)0, NULL, 0, (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK));
 1567         //if (widget != border)
 1568         //  gtk_drag_dest_set(widget, (GtkDestDefaults)0, NULL, 0, (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK));
 1569     }
 1570     else
 1571     {
 1572         gtk_drag_dest_unset(border);
 1573         //if (widget != border)
 1574         //  gtk_drag_dest_unset(widget);
 1575     }
 1576 }
 1577 
 1578 /*********************************************************************
 1579 
 1580 Internal
 1581 
 1582 **********************************************************************/
 1583 
 1584 void gControl::connectParent()
 1585 {
 1586     if (pr)
 1587         pr->insert(this, true);
 1588 
 1589     // BM: Widget has been created, so we can set its cursor if application is busy
 1590     if (gApplication::isBusy() && mustUpdateCursor())
 1591         setMouse(mouse());
 1592 }
 1593 
 1594 gColor gControl::getFrameColor()
 1595 {
 1596     return gDesktop::getColor(gDesktop::LIGHT_FOREGROUND);
 1597 }
 1598 
 1599 #ifdef GTK3
 1600 void gControl::drawBorder(cairo_t *cr)
 1601 {
 1602     /*if (getFrameBorder() != BORDER_NONE)
 1603         fprintf(stderr, "gControl::drawBorder: %s: %d %d\n", name(), width(), height());*/
 1604     gt_draw_border(cr, gtk_widget_get_style_context(widget), gtk_widget_get_state_flags(widget), getFrameBorder(), getFrameColor(), 0, 0, width(), height(), use_base);
 1605 }
 1606 #else
 1607 void gControl::drawBorder(GdkEventExpose *e)
 1608 {
 1609     GdkWindow *win;
 1610     GtkShadowType shadow;
 1611     gint x, y, w, h;
 1612     cairo_t *cr;
 1613     GtkWidget *wid;
 1614     GtkAllocation a;
 1615 
 1616     if (getFrameBorder() == BORDER_NONE)
 1617         return;
 1618 
 1619     x = 0;
 1620     y = 0;
 1621     w = width();
 1622     h = height();
 1623 
 1624     if (frame)
 1625         wid = frame;
 1626     else
 1627         wid = widget;
 1628 
 1629     if (GTK_IS_LAYOUT(wid))
 1630         win = gtk_layout_get_bin_window(GTK_LAYOUT(wid));
 1631     else
 1632         win = gtk_widget_get_window(wid);
 1633 
 1634     gtk_widget_get_allocation(wid, &a);
 1635     x = a.x;
 1636     y = a.y;
 1637 
 1638     if (w < 1 || h < 1)
 1639         return;
 1640 
 1641     switch (getFrameBorder())
 1642     {
 1643         case BORDER_PLAIN:
 1644 
 1645             cr = gdk_cairo_create(win);
 1646             gt_cairo_draw_rect(cr, x, y, w, h, getFrameColor());
 1647             cairo_destroy(cr);
 1648             return;
 1649 
 1650         case BORDER_SUNKEN: shadow = GTK_SHADOW_IN; break;
 1651         case BORDER_RAISED: shadow = GTK_SHADOW_OUT; break;
 1652         case BORDER_ETCHED: shadow = GTK_SHADOW_ETCHED_IN; break;
 1653 
 1654         default:
 1655             return;
 1656     }
 1657 
 1658     GdkRectangle clip;
 1659     gdk_region_get_clipbox(e->region, &clip);
 1660     GtkStyle *st = gtk_widget_get_style(widget);
 1661     if (use_base)
 1662         gtk_paint_box(st, win, GTK_STATE_NORMAL, shadow, &clip, widget, "entry", x, y, w, h);
 1663     else
 1664         gtk_paint_shadow(st, win, GTK_STATE_NORMAL, shadow, &clip, widget, NULL, x, y, w, h);
 1665 }
 1666 #endif
 1667 
 1668 /*static void cb_size_allocate(GtkWidget *wid, GtkAllocation *a, gContainer *container)
 1669 {
 1670     if (!container->isTopLevel())
 1671         container->performArrange();
 1672 }*/
 1673 
 1674 
 1675 /*
 1676     The different cases managed by gControl::realize()
 1677 
 1678     border     frame      widget
 1679         0          0          W
 1680         B          0          W
 1681         0          F          W
 1682         B          F          W
 1683 */
 1684 
 1685 static void add_container(GtkWidget *parent, GtkWidget *child)
 1686 {
 1687     GtkWidget *ch;
 1688 
 1689     for(;;)
 1690     {
 1691         if (!GTK_IS_BIN(parent))
 1692             break;
 1693 
 1694         ch = gtk_bin_get_child(GTK_BIN(parent));
 1695         if (!ch)
 1696             break;
 1697 
 1698         parent = ch;
 1699     }
 1700 
 1701     gtk_container_add(GTK_CONTAINER(parent), child);
 1702 }
 1703 
 1704 void gControl::registerControl()
 1705 {
 1706     gt_register_control(border, this);
 1707 }
 1708 
 1709 #ifdef GTK3
 1710 /*static gboolean cb_clip_children(GtkWidget *wid, GdkEventExpose *e, gContainer *d)
 1711 {
 1712     cairo_region_t *me;
 1713     GtkAllocation a;
 1714 
 1715     gtk_widget_get_allocation(wid, &a);
 1716     me = cairo_region_create_rectangle((cairo_rectangle_int_t *)&a);
 1717 
 1718     cairo_region_intersect(e->region, me);
 1719 
 1720     cairo_region_destroy(me);
 1721 
 1722     if (cairo_region_is_empty(e->region))
 1723         return TRUE;
 1724 
 1725     return FALSE;
 1726 }*/
 1727 #else
 1728 static gboolean cb_clip_children(GtkWidget *wid, GdkEventExpose *e, gContainer *d)
 1729 {
 1730     GdkRegion *me;
 1731     GtkAllocation a;
 1732 
 1733     gtk_widget_get_allocation(wid, &a);
 1734     me = gdk_region_rectangle((GdkRectangle *)&a);
 1735 
 1736     gdk_region_intersect(e->region, me);
 1737 
 1738     gdk_region_destroy(me);
 1739 
 1740     if (gdk_region_empty(e->region))
 1741         return TRUE;
 1742 
 1743     return FALSE;
 1744 }
 1745 #endif
 1746 
 1747 #if 0
 1748 static gboolean cb_clip_by_parent(GtkWidget *wid, GdkEventExpose *e, gControl *d)
 1749 {
 1750     GdkRegion *preg;
 1751     GdkRectangle prect = { 0, 0, d->parent()->width() - d->x(), d->parent()->height() - d->y() };
 1752 
 1753     fprintf(stderr, "area = %d %d %d %d  prect = %d %d %d %d\n",
 1754                     e->area.x, e->area.y, e->area.width, e->area.height,
 1755                     prect.x, prect.y, prect.width, prect.height);
 1756 
 1757     preg = gdk_region_rectangle(&prect);
 1758 
 1759     gdk_region_intersect(e->region, preg);
 1760 
 1761     gdk_region_destroy(preg);
 1762 
 1763     if (gdk_region_empty(e->region))
 1764         return TRUE;
 1765 
 1766     gdk_region_get_clipbox(e->region, &prect);
 1767     e->area = prect;
 1768     fprintf(stderr, "--> %d %d %d %d\n", prect.x, prect.y, prect.width, prect.height);
 1769 
 1770     return FALSE;
 1771 }
 1772 #endif
 1773 
 1774 #ifdef GTK3
 1775 
 1776 //fprintf(stderr, "get_preferred_width [%p %s] %p\n", klass, G_OBJECT_TYPE_NAME(widget), klass->_gtk_reserved2);
 1777 //fprintf(stderr, "get_preferred_height [%p %s] %p\n", klass, G_OBJECT_TYPE_NAME(widget), klass->_gtk_reserved3);
 1778 
 1779 //#define must_patch(_widget) (gt_get_control(_widget) != NULL)
 1780 
 1781 static bool _do_not_patch = false;
 1782 
 1783 static bool must_patch(GtkWidget *widget)
 1784 {
 1785     GtkWidget *parent;
 1786     gControl *parent_control;
 1787 
 1788     if (_do_not_patch)
 1789         return false;
 1790 
 1791     if (gt_get_control(widget))
 1792     {
 1793         //fprintf(stderr, "must_patch: %p -> 1\n", widget);
 1794         return true;
 1795     }
 1796 
 1797     parent = gtk_widget_get_parent(widget);
 1798     if (!parent)
 1799     {
 1800         //fprintf(stderr, "must_patch: %p -> 0\n", widget);
 1801         return false;
 1802     }
 1803     
 1804     if (GTK_IS_NOTEBOOK(parent) && GTK_IS_FIXED(widget))
 1805         return true;
 1806     
 1807     if (GTK_IS_SCROLLED_WINDOW(parent))
 1808     {
 1809         parent = gtk_widget_get_parent(parent);
 1810         if (!parent)
 1811             return false;
 1812     }
 1813     
 1814     if (GTK_IS_ENTRY(widget))
 1815     {
 1816         parent = gtk_widget_get_parent(parent);
 1817         if (GTK_IS_COMBO_BOX(parent))
 1818             return true;
 1819     }
 1820 
 1821     parent_control = gt_get_control(parent);
 1822     if (!parent_control)
 1823         return false;
 1824 
 1825     return (parent_control->widget == widget || (GtkWidget *)parent_control->_scroll == widget);
 1826 }
 1827 
 1828 #include "gb.gtk.patch.h"
 1829 
 1830 PATCH_DECLARE(GTK_TYPE_WINDOW)
 1831 PATCH_DECLARE(GTK_TYPE_ENTRY)
 1832 PATCH_DECLARE(GTK_TYPE_COMBO_BOX)
 1833 PATCH_DECLARE(GTK_TYPE_SPIN_BUTTON)
 1834 PATCH_DECLARE(GTK_TYPE_BUTTON)
 1835 PATCH_DECLARE(GTK_TYPE_FIXED)
 1836 PATCH_DECLARE(GTK_TYPE_EVENT_BOX)
 1837 //PATCH_DECLARE(GTK_TYPE_ALIGNMENT)
 1838 PATCH_DECLARE(GTK_TYPE_BOX)
 1839 PATCH_DECLARE(GTK_TYPE_TOGGLE_BUTTON)
 1840 PATCH_DECLARE(GTK_TYPE_SCROLLED_WINDOW)
 1841 PATCH_DECLARE(GTK_TYPE_CHECK_BUTTON)
 1842 PATCH_DECLARE(GTK_TYPE_RADIO_BUTTON)
 1843 PATCH_DECLARE(GTK_TYPE_NOTEBOOK)
 1844 PATCH_DECLARE(GTK_TYPE_TEXT_VIEW)
 1845 PATCH_DECLARE(GTK_TYPE_SCROLLBAR)
 1846 PATCH_DECLARE(GTK_TYPE_SCALE)
 1847 
 1848 #if GTK_CHECK_VERSION(3,10,0)
 1849 PATCH_DECLARE_BASELINE(GTK_TYPE_ENTRY)
 1850 PATCH_DECLARE_BASELINE(GTK_TYPE_COMBO_BOX)
 1851 PATCH_DECLARE_BASELINE(GTK_TYPE_SPIN_BUTTON)
 1852 PATCH_DECLARE_BASELINE(GTK_TYPE_BUTTON)
 1853 #endif
 1854 
 1855 void gt_patch_control(GtkWidget *widget)
 1856 {
 1857     PATCH_CLASS(widget, GTK_TYPE_WINDOW)
 1858     else PATCH_CLASS_BASELINE(widget, GTK_TYPE_ENTRY)
 1859     else PATCH_CLASS_BASELINE(widget, GTK_TYPE_SPIN_BUTTON)
 1860     else PATCH_CLASS_BASELINE(widget, GTK_TYPE_BUTTON)
 1861     else PATCH_CLASS(widget, GTK_TYPE_FIXED)
 1862     else PATCH_CLASS(widget, GTK_TYPE_EVENT_BOX)
 1863     //else PATCH_CLASS(widget, GTK_TYPE_ALIGNMENT)
 1864     else PATCH_CLASS(widget, GTK_TYPE_BOX)
 1865     else PATCH_CLASS(widget, GTK_TYPE_TOGGLE_BUTTON)
 1866     else PATCH_CLASS(widget, GTK_TYPE_SCROLLED_WINDOW)
 1867     else PATCH_CLASS(widget, GTK_TYPE_CHECK_BUTTON)
 1868     else PATCH_CLASS(widget, GTK_TYPE_RADIO_BUTTON)
 1869     else PATCH_CLASS(widget, GTK_TYPE_NOTEBOOK)
 1870     else PATCH_CLASS(widget, GTK_TYPE_TEXT_VIEW)
 1871     else PATCH_CLASS(widget, GTK_TYPE_SCROLLBAR)
 1872     else PATCH_CLASS(widget, GTK_TYPE_SCALE)
 1873     else PATCH_CLASS_BASELINE(widget, GTK_TYPE_COMBO_BOX)
 1874     else PATCH_CLASS(widget, GTK_TYPE_TEXT_VIEW)
 1875 }
 1876 
 1877 #endif
 1878 
 1879 void gControl::setMinimumSize()
 1880 {
 1881     #ifdef GTK3
 1882 
 1883     if (isContainer())
 1884     {
 1885         _min_w = _min_h = 1;
 1886     }
 1887     else
 1888     {
 1889         GtkRequisition minimum_size, natural_size;
 1890         bool mapped = gtk_widget_get_mapped(border);
 1891         
 1892         if (!mapped)
 1893             gtk_widget_show(border);
 1894             
 1895         _do_not_patch = true;
 1896         gtk_widget_get_preferred_size(widget, &minimum_size, &natural_size);
 1897         _do_not_patch = false;
 1898         
 1899         if (!mapped)
 1900             gtk_widget_hide(border);
 1901         
 1902         //fprintf(stderr, "gtk_widget_get_preferred_size: %s: min = %d %d / nat = %d %d\n", GB.GetClassName(hFree), minimum_size.width, minimum_size.height, natural_size.width, natural_size.height);
 1903 
 1904         _min_w = minimum_size.width;
 1905         _min_h = minimum_size.height;
 1906     }
 1907     
 1908     #else
 1909     
 1910     _min_w = _min_h = 1;
 1911         
 1912     #endif
 1913 }
 1914 
 1915 
 1916 void gControl::connectBorder()
 1917 {
 1918 }
 1919 
 1920 void gControl::realize(bool draw_frame)
 1921 {
 1922     if (!_scroll)
 1923     {
 1924         if (!border)
 1925             border = widget;
 1926 
 1927         if (frame)
 1928         {
 1929             if (border != frame && border != widget)
 1930                 add_container(border, frame);
 1931             if (frame != widget)
 1932                 add_container(frame, widget);
 1933         }
 1934         else if (border != widget)
 1935             add_container(border, widget);
 1936     }
 1937 
 1938 #ifdef GTK3
 1939     gt_patch_control(border);
 1940     if (widget && widget != border)
 1941         gt_patch_control(widget);
 1942 #endif
 1943 
 1944     connectParent();
 1945     connectBorder();
 1946     
 1947     setMinimumSize();
 1948     resize(Max(8, _min_w), Max(8, _min_h), true);
 1949     initSignals();
 1950 
 1951     if (!_no_background && !gtk_widget_get_has_window(border))
 1952         ON_DRAW_BEFORE(border, this, cb_background_expose, cb_background_draw);
 1953 
 1954     if (draw_frame && frame)
 1955         ON_DRAW_BEFORE(frame, this, cb_frame_expose, cb_frame_draw);
 1956     
 1957 #ifndef GTK3
 1958     if (isContainer() && !gtk_widget_get_has_window(widget))
 1959         g_signal_connect(G_OBJECT(widget), "expose-event", G_CALLBACK(cb_clip_children), (gpointer)this);
 1960 #endif
 1961 
 1962     //if (isContainer() && widget != border)
 1963     //  g_signal_connect(G_OBJECT(widget), "size-allocate", G_CALLBACK(cb_size_allocate), (gpointer)this);
 1964 
 1965     gtk_widget_add_events(widget, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
 1966         | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK
 1967         | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
 1968 
 1969     if (widget != border && (GTK_IS_WINDOW(border) || (GTK_IS_EVENT_BOX(border) && !gtk_event_box_get_visible_window(GTK_EVENT_BOX(border)))))
 1970     {
 1971         gtk_widget_add_events(border, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
 1972             | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK
 1973             | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
 1974     }
 1975 
 1976     registerControl();
 1977     updateFont();
 1978 }
 1979 
 1980 void gControl::realizeScrolledWindow(GtkWidget *wid, bool doNotRealize)
 1981 {
 1982     _scroll = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL));
 1983 
 1984 #ifdef GTK3
 1985     PATCH_CLASS(_scroll, GTK_TYPE_SCROLLED_WINDOW)
 1986     PATCH_CLASS(wid, GTK_TYPE_TEXT_VIEW)
 1987 #endif
 1988 
 1989 #ifdef GTK3
 1990         border = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
 1991         gtk_widget_set_hexpand(wid, TRUE);
 1992 #else
 1993         border = gtk_alignment_new(0, 0, 1, 1);
 1994 #endif
 1995     gtk_widget_set_redraw_on_allocate(border, TRUE);
 1996     widget = wid;
 1997     frame = border;
 1998     _no_auto_grab = true;
 1999 
 2000     //gtk_container_add(GTK_CONTAINER(border), GTK_WIDGET(_scroll));
 2001     gtk_scrolled_window_set_policy(_scroll, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 2002     gtk_scrolled_window_set_shadow_type(_scroll, GTK_SHADOW_NONE);
 2003     gtk_container_add(GTK_CONTAINER(border), GTK_WIDGET(_scroll));
 2004     gtk_container_add(GTK_CONTAINER(_scroll), widget);
 2005 
 2006     if (!doNotRealize)
 2007         realize(true);
 2008     else
 2009         registerControl();
 2010 
 2011     updateFont();
 2012     
 2013     gtk_widget_show_all(border);
 2014 }
 2015 
 2016 void gControl::updateBorder()
 2017 {
 2018     int pad;
 2019 
 2020     if (!frame)
 2021         return;
 2022 
 2023 #if GTK3
 2024     if (!GTK_IS_BOX(frame))
 2025 #else
 2026     if (!GTK_IS_ALIGNMENT(frame))
 2027 #endif
 2028     {
 2029         refresh();
 2030         return;
 2031     }
 2032 
 2033     switch (frame_border)
 2034     {
 2035         case BORDER_NONE: pad = 0; break;
 2036         case BORDER_PLAIN: pad = 1; break;
 2037         default: pad = gApplication::getFrameWidth(); break;
 2038     }
 2039 
 2040     if ((int)frame_padding > pad)
 2041         pad = frame_padding;
 2042 
 2043 #if GTK3
 2044     g_object_set(widget, "margin", pad, NULL);
 2045 #else
 2046     gtk_alignment_set_padding(GTK_ALIGNMENT(frame), pad, pad, pad, pad);
 2047     refresh();
 2048 #endif
 2049     //gtk_widget_queue_draw(frame);
 2050 }
 2051 
 2052 int gControl::getFrameWidth() const
 2053 {
 2054     guint p;
 2055 
 2056     if (frame)
 2057     {
 2058 #if GTK3
 2059         if (GTK_IS_BOX(frame))
 2060         {
 2061             g_object_get(widget, "margin", &p, NULL);
 2062             return p;
 2063         }
 2064 #else
 2065         if (GTK_IS_ALIGNMENT(frame))
 2066         {
 2067             gtk_alignment_get_padding(GTK_ALIGNMENT(frame), &p, NULL, NULL, NULL);
 2068             return p;
 2069         }
 2070 #endif
 2071     }
 2072 
 2073     /*if (_scroll)
 2074     {
 2075         if (gtk_scrolled_window_get_shadow_type(_scroll) == GTK_SHADOW_NONE)
 2076             return 0;
 2077         else
 2078             return gApplication::getFrameWidth();
 2079     }*/
 2080 
 2081     switch (frame_border)
 2082     {
 2083         case BORDER_NONE: p = 0; break;
 2084         case BORDER_PLAIN: p = 1; break;
 2085         default: p = gApplication::getFrameWidth(); break;
 2086     }
 2087     return p;
 2088 }
 2089 
 2090 void gControl::setFrameBorder(int border)
 2091 {
 2092     if (border < BORDER_NONE || border > BORDER_ETCHED)
 2093         return;
 2094 
 2095     frame_border = border;
 2096     updateBorder();
 2097 }
 2098 
 2099 bool gControl::hasBorder() const
 2100 {
 2101     return getFrameBorder() != BORDER_NONE;
 2102 }
 2103 
 2104 void gControl::setBorder(bool vl)
 2105 {
 2106     setFrameBorder(vl ? BORDER_SUNKEN : BORDER_NONE);
 2107     _has_border = vl;
 2108 }
 2109 
 2110 
 2111 void gControl::setFramePadding(int padding)
 2112 {
 2113     if (padding < 0)
 2114         padding = 0;
 2115     frame_padding = padding;
 2116     updateBorder();
 2117 }
 2118 
 2119 
 2120 void gControl::setName(char *name)
 2121 {
 2122     if (_name) g_free(_name);
 2123     _name = NULL;
 2124     if (name) _name = g_strdup(name);
 2125 }
 2126 
 2127 gColor gControl::defaultBackground() const
 2128 {
 2129     return gDesktop::getColor(gDesktop::BACKGROUND, !isEnabled());
 2130 }
 2131 
 2132 #ifdef GTK3
 2133 
 2134 GtkWidget *gControl::getStyleSheetWidget()
 2135 {
 2136     return border;
 2137 }
 2138 
 2139 const char *gControl::getStyleSheetColorNode()
 2140 {
 2141     return "";
 2142 }
 2143 
 2144 const char *gControl::getStyleSheetFontNode()
 2145 {
 2146     return "";
 2147 }
 2148 
 2149 void gControl::customStyleSheet(GString *css)
 2150 {
 2151 }
 2152 
 2153 void gControl::setStyleSheetNode(GString *css, const char *node)
 2154 {
 2155     if (node == _css_node)
 2156         return;
 2157     
 2158     if (node && _css_node && !::strcmp(node, _css_node))
 2159         return;
 2160     
 2161     if (_css_node)
 2162         g_string_append(css, "}\n");
 2163     
 2164     _css_node = node;
 2165     
 2166     if (!node)
 2167         return;
 2168     
 2169     if (!_has_css_id)
 2170     {
 2171         gt_widget_set_name(getStyleSheetWidget(), name());
 2172         _has_css_id = true;
 2173     }
 2174 
 2175     g_string_append_printf(css, "#%s %s {\ntransition:none;\n", gtk_widget_get_name(getStyleSheetWidget()), node);
 2176 }
 2177 
 2178 void gControl::updateStyleSheet(bool dirty)
 2179 {
 2180     GString *css;
 2181     gColor bg, fg;
 2182     
 2183     if (dirty)
 2184         _style_dirty = true;
 2185 
 2186     if (isContainer())
 2187     {
 2188         gContainer *cont = (gContainer *)this;
 2189         
 2190         if (_no_style_without_child && cont->childCount() == 0)
 2191             return;
 2192 
 2193         if (!dirty)
 2194         {
 2195             for (int i = 0; i < cont->childCount(); i++)
 2196                 cont->child(i)->updateStyleSheet(false);
 2197         }
 2198     }
 2199     
 2200     if (!isReallyVisible() || !_style_dirty)
 2201         return;
 2202 
 2203     bg = _no_background ? background() : COLOR_DEFAULT;
 2204     fg = foreground(); //realForeground();
 2205 
 2206     css = g_string_new(NULL);
 2207     _css_node = NULL;
 2208     
 2209     if (bg != COLOR_DEFAULT || fg != COLOR_DEFAULT)
 2210     {
 2211         setStyleSheetNode(css, getStyleSheetColorNode());
 2212         gt_css_add_color(css, bg, fg);
 2213     }
 2214     
 2215     if (_font)
 2216     {
 2217         setStyleSheetNode(css, getStyleSheetFontNode());
 2218         gt_css_add_font(css, _font);
 2219     }
 2220 
 2221     customStyleSheet(css);
 2222 
 2223     setStyleSheetNode(css, NULL);
 2224     
 2225     gt_define_style_sheet(&_css, css);
 2226     
 2227     /*if (_css)
 2228     {
 2229         char *css_str = gtk_css_provider_to_string(GTK_CSS_PROVIDER(_css));
 2230         fprintf(stderr, "---- %s\n%s", gtk_widget_get_name(getStyleSheetWidget()), css_str);
 2231         g_free(css_str);
 2232     }*/
 2233     
 2234     _style_dirty = false;
 2235 }
 2236 
 2237 gColor gControl::realBackground(bool no_default)
 2238 {
 2239     if (_bg != COLOR_DEFAULT)
 2240         return _bg;
 2241     else
 2242         return no_default ? defaultBackground() : COLOR_DEFAULT;
 2243 }
 2244 
 2245 void gControl::setRealBackground(gColor color)
 2246 {
 2247 }
 2248 
 2249 void gControl::setBackground(gColor color)
 2250 {
 2251     if (_bg == color)
 2252         return;
 2253     
 2254     _bg = color;
 2255     updateStyleSheet(true);
 2256     updateColor();
 2257 }
 2258 
 2259 gColor gControl::realForeground(bool no_default)
 2260 {
 2261     if (_fg != COLOR_DEFAULT)
 2262         return _fg;
 2263     else if (pr)
 2264         return pr->realForeground(no_default);
 2265     else
 2266         return no_default ? gDesktop::getColor(gDesktop::FOREGROUND) : COLOR_DEFAULT;
 2267 }
 2268 
 2269 void gControl::setRealForeground(gColor color)
 2270 {
 2271 }
 2272 
 2273 void gControl::setForeground(gColor color)
 2274 {
 2275     if (_fg == color)
 2276         return;
 2277     
 2278     _fg = color;
 2279     _fg_set = color != COLOR_DEFAULT;
 2280 #ifdef GTK3
 2281     updateStyleSheet(true);
 2282 #endif
 2283     //gt_widget_set_color(border, TRUE, _fg, _fg_name, &_fg_default);
 2284     updateColor();
 2285     /*if (::strcmp(name(), "dwgInfo") == 0)
 2286         fprintf(stderr, "setForeground: %08X\n", _fg);*/
 2287 }
 2288 
 2289 #else
 2290 
 2291 gColor gControl::realBackground(bool no_default)
 2292 {
 2293     if (_bg_set)
 2294         return use_base ? get_gdk_base_color(widget, isEnabled()) : get_gdk_bg_color(widget, isEnabled());
 2295     else
 2296         return no_default ? defaultBackground() : COLOR_DEFAULT;
 2297 }
 2298 
 2299 static void set_background(GtkWidget *widget, gColor color, bool use_base)
 2300 {
 2301     if (use_base)
 2302         set_gdk_base_color(widget, color);
 2303     else
 2304         set_gdk_bg_color(widget, color);
 2305 }
 2306 
 2307 void gControl::setRealBackground(gColor color)
 2308 {
 2309     set_background(border, color, use_base);
 2310     if (border != frame && GTK_IS_WIDGET(frame))
 2311         set_background(frame, color, use_base);
 2312     if (frame != widget)
 2313         set_background(widget, color, use_base);
 2314 }
 2315 
 2316 void gControl::setBackground(gColor color)
 2317 {
 2318     _bg = color;
 2319     _bg_set = color != COLOR_DEFAULT;
 2320 
 2321     if (!_bg_set)
 2322     {
 2323         if (pr && !use_base)
 2324             color = pr->realBackground();
 2325     }
 2326 
 2327     setRealBackground(color);
 2328 }
 2329 
 2330 gColor gControl::realForeground(bool no_default)
 2331 {
 2332     if (_fg_set)
 2333         return use_base ? get_gdk_text_color(widget, isEnabled()) : get_gdk_fg_color(widget, isEnabled());
 2334     else if (pr)
 2335         return pr->realForeground(no_default);
 2336     else
 2337         return no_default ? gDesktop::getColor(gDesktop::FOREGROUND) : COLOR_DEFAULT;
 2338 }
 2339 
 2340 static void set_foreground(GtkWidget *widget, gColor color, bool use_base)
 2341 {
 2342     if (use_base)
 2343         set_gdk_text_color(widget, color);
 2344     else
 2345         set_gdk_fg_color(widget, color);
 2346 }
 2347 
 2348 void gControl::setRealForeground(gColor color)
 2349 {
 2350     set_foreground(widget, color, use_base);
 2351 }
 2352 
 2353 void gControl::setForeground(gColor color)
 2354 {
 2355     _fg = color;
 2356     _fg_set = color != COLOR_DEFAULT;
 2357 
 2358     if (!_fg_set)
 2359     {
 2360         if (pr)
 2361             color = pr->realForeground();
 2362     }
 2363 
 2364     setRealForeground(color);
 2365 }
 2366 
 2367 #endif
 2368 
 2369 void gControl::emit(void *signal)
 2370 {
 2371     if (!signal || locked())
 2372         return;
 2373     (*((void (*)(gControl *))signal))(this);
 2374 }
 2375 
 2376 void gControl::emit(void *signal, intptr_t arg)
 2377 {
 2378     if (!signal || locked())
 2379         return;
 2380     (*((void (*)(gControl *, intptr_t))signal))(this, arg);
 2381 }
 2382 
 2383 void gControl::reparent(gContainer *newpr, int x, int y)
 2384 {
 2385     gContainer *oldpr;
 2386     bool was_visible = isVisible();
 2387 
 2388     // newpr can be equal to pr: for example, to move a control for one
 2389     // tab to another tab of the same TabStrip!
 2390 
 2391     if (!newpr || !newpr->getContainer())
 2392         return;
 2393 
 2394     if (pr == newpr && gtk_widget_get_parent(border) == newpr->getContainer())
 2395     {
 2396         move(x, y);
 2397         return;
 2398     }
 2399 
 2400     if (was_visible) hide();
 2401     //gtk_widget_unrealize(border);
 2402 
 2403     oldpr = pr;
 2404     pr = newpr;
 2405 
 2406     if (oldpr == newpr)
 2407     {
 2408         gt_widget_reparent(border, newpr->getContainer());
 2409         oldpr->performArrange();
 2410     }
 2411     else
 2412     {
 2413         if (oldpr)
 2414         {
 2415             gt_widget_reparent(border, newpr->getContainer());
 2416             oldpr->remove(this);
 2417             oldpr->performArrange();
 2418         }
 2419 
 2420         newpr->insert(this);
 2421     }
 2422 
 2423     //gtk_widget_realize(border);
 2424     bufX = !x;
 2425     move(x, y);
 2426     if (was_visible)
 2427     {
 2428         //fprintf(stderr, "was_visible\n");
 2429         show();
 2430     }
 2431 }
 2432 
 2433 int gControl::scrollX()
 2434 {
 2435     if (!_scroll)
 2436         return 0;
 2437 
 2438     return (int)gtk_adjustment_get_value(gtk_scrolled_window_get_hadjustment(_scroll));
 2439 }
 2440 
 2441 int gControl::scrollY()
 2442 {
 2443     if (!_scroll)
 2444         return 0;
 2445 
 2446     return (int)gtk_adjustment_get_value(gtk_scrolled_window_get_vadjustment(_scroll));
 2447 }
 2448 
 2449 void gControl::setScrollX(int vl)
 2450 {
 2451     GtkAdjustment* adj;
 2452     int max;
 2453 
 2454     if (!_scroll)
 2455         return;
 2456 
 2457     adj = gtk_scrolled_window_get_hadjustment(_scroll);
 2458 
 2459     max = (int)(gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj));
 2460 
 2461     if (vl < 0)
 2462         vl = 0;
 2463     else if (vl > max)
 2464         vl = max;
 2465 
 2466     gtk_adjustment_set_value(adj, (gdouble)vl);
 2467 }
 2468 
 2469 void gControl::setScrollY(int vl)
 2470 {
 2471     GtkAdjustment* adj;
 2472     int max;
 2473 
 2474     if (!_scroll)
 2475         return;
 2476 
 2477     adj = gtk_scrolled_window_get_vadjustment(_scroll);
 2478 
 2479     max = (int)(gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj));
 2480 
 2481     if (vl < 0)
 2482         vl = 0;
 2483     else if (vl > max)
 2484         vl = max;
 2485 
 2486     gtk_adjustment_set_value(adj, (gdouble)vl);
 2487 }
 2488 
 2489 void gControl::scroll(int x, int y)
 2490 {
 2491     setScrollX(x);
 2492     setScrollY(y);
 2493 }
 2494 
 2495 /*int gControl::scrollWidth()
 2496 {
 2497     return widget->requisition.width;
 2498 }
 2499 
 2500 int gControl::scrollHeight()
 2501 {
 2502     return widget->requisition.height;
 2503 }*/
 2504 
 2505 void gControl::setScrollBar(int vl)
 2506 {
 2507     if (!_scroll)
 2508         return;
 2509 
 2510     _scrollbar = vl & 3;
 2511     updateScrollBar();
 2512 }
 2513 
 2514 void gControl::updateScrollBar()
 2515 {
 2516     if (!_scroll)
 2517         return;
 2518 
 2519     switch(_scrollbar)
 2520     {
 2521         case SCROLL_NONE:
 2522             gtk_scrolled_window_set_policy(_scroll, GTK_POLICY_NEVER, GTK_POLICY_NEVER);
 2523             break;
 2524         case SCROLL_HORIZONTAL:
 2525             gtk_scrolled_window_set_policy(_scroll, GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
 2526             break;
 2527         case SCROLL_VERTICAL:
 2528             gtk_scrolled_window_set_policy(_scroll, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
 2529             break;
 2530         case SCROLL_BOTH:
 2531             gtk_scrolled_window_set_policy(_scroll, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 2532             break;
 2533     }
 2534 }
 2535 
 2536 bool gControl::isTracking() const
 2537 {
 2538     if (_proxy)
 2539         return _proxy->isTracking();
 2540     else
 2541         return _tracking;
 2542 }
 2543 
 2544 void gControl::setTracking(bool v)
 2545 {
 2546     if (_proxy)
 2547         _proxy->setTracking(v);
 2548     else
 2549         _tracking = v;
 2550     /*
 2551     GtkWidget *wid;
 2552 
 2553     if (GTK_IS_EVENT_BOX(border))
 2554         wid = border;
 2555     else
 2556         wid = widget;
 2557 
 2558     if (v != _tracking)
 2559     {
 2560         uint event_mask = gtk_widget_get_events(wid);
 2561         _tracking = v;
 2562         if (v)
 2563         {
 2564             _old_tracking = event_mask & GDK_POINTER_MOTION_MASK;
 2565             event_mask |= GDK_POINTER_MOTION_MASK;
 2566         }
 2567         else
 2568         {
 2569             event_mask &= ~GDK_POINTER_MOTION_MASK;
 2570         }
 2571 
 2572         if (!_old_tracking)
 2573         {
 2574             gtk_widget_unrealize(wid);
 2575             gtk_widget_set_events(wid, event_mask);
 2576             gtk_widget_realize(wid);
 2577         }
 2578     }
 2579     */
 2580 }
 2581 
 2582 bool gControl::grab()
 2583 {
 2584     gControl *old_control_grab;
 2585     bool save_tracking;
 2586 
 2587     if (_grab)
 2588         return false;
 2589 
 2590     if (gt_grab(border, FALSE, gApplication::lastEventTime()))
 2591         return true;
 2592 
 2593     _grab = true;
 2594     save_tracking = _tracking;
 2595     _tracking = true;
 2596 
 2597     old_control_grab = gApplication::_control_grab;
 2598     gApplication::_control_grab = this;
 2599 
 2600     gApplication::enterLoop(this);
 2601 
 2602     gApplication::_control_grab = old_control_grab;
 2603 
 2604     gt_ungrab();
 2605 
 2606     _tracking = save_tracking;
 2607     _grab = false;
 2608     return false;
 2609 }
 2610 
 2611 bool gControl::hovered()
 2612 {
 2613     //int x, y, xm, ym;
 2614 
 2615     if (!isVisible())
 2616         return false;
 2617     else
 2618         return _inside;
 2619 
 2620     /*getScreenPos(&x, &y);
 2621     gMouse::getScreenPos(&xm, &ym);
 2622 
 2623     return (xm >= x && ym >= y && xm < (x + width()) && ym < (y + height()));*/
 2624 }
 2625 
 2626 bool gControl::setProxy(gControl *proxy)
 2627 {
 2628     gControl *check = proxy;
 2629 
 2630     while (check)
 2631     {
 2632         if (check == this)
 2633             return true;
 2634 
 2635         check = check->_proxy;
 2636     }
 2637 
 2638     if (_proxy)
 2639         _proxy->_proxy_for = NULL;
 2640 
 2641     _proxy = proxy;
 2642 
 2643     if (_proxy)
 2644         _proxy->_proxy_for = this;
 2645 
 2646     return false;
 2647 }
 2648 
 2649 void gControl::setNoTabFocus(bool v)
 2650 {
 2651     if (_proxy)
 2652     {
 2653         _proxy->setNoTabFocus(v);
 2654         return;
 2655     }
 2656     
 2657     if (_no_tab_focus == v)
 2658         return;
 2659 
 2660     _no_tab_focus = v;
 2661 }
 2662 
 2663 bool gControl::isNoTabFocus() const
 2664 {
 2665     if (_proxy)
 2666         return _proxy->isNoTabFocus();
 2667     else
 2668         return _no_tab_focus;
 2669 }
 2670 
 2671 #ifdef GTK3
 2672 void gControl::onEnterEvent()
 2673 {
 2674 }
 2675 
 2676 void gControl::onLeaveEvent()
 2677 {
 2678 }
 2679 #endif
 2680 
 2681 void gControl::emitEnterEvent(bool no_leave)
 2682 {
 2683     gContainer *cont;
 2684     
 2685     #if DEBUG_ENTER_LEAVE
 2686     fprintf(stderr, "========== START ENTER %s (%d)\n", name(), no_leave);
 2687     #endif
 2688 
 2689     if (parent())
 2690         parent()->emitEnterEvent(true);
 2691 
 2692     if (!no_leave && isContainer())
 2693     {
 2694         cont = (gContainer *)this;
 2695         int i;
 2696 
 2697         for (i = 0; i < cont->childCount(); i++)
 2698             cont->child(i)->emitLeaveEvent();
 2699     }
 2700 
 2701     gApplication::_enter = this;
 2702 
 2703     if (gApplication::_leave)
 2704     {
 2705         if (gApplication::_leave == this || gApplication::_leave->isAncestorOf(this))
 2706             gApplication::_leave = NULL;
 2707     }
 2708 
 2709     if (_inside)
 2710         return;
 2711     
 2712     _inside = true;
 2713     
 2714     #ifdef GTK3
 2715     onEnterEvent();
 2716     #endif
 2717 
 2718     if (!no_leave)
 2719         setMouse(mouse());
 2720 
 2721     #if DEBUG_ENTER_LEAVE
 2722     fprintf(stderr, ">>>>>>>>>> END ENTER %s\n", name());
 2723     #endif
 2724 
 2725     if (gApplication::_ignore_until_next_enter)
 2726     {
 2727         #if DEBUG_ENTER_LEAVE
 2728         fprintf(stderr, "ignore next enter for %s\n", name());
 2729         #endif
 2730         if (gApplication::_ignore_until_next_enter == this)
 2731             gApplication::_ignore_until_next_enter = NULL;
 2732         return;
 2733     }
 2734 
 2735     //fprintf(stderr, "RAISE ENTER: %s\n", name());
 2736     emit(SIGNAL(onEnterLeave), gEvent_Enter);
 2737 }
 2738 
 2739 void gControl::emitLeaveEvent()
 2740 {
 2741     if (gApplication::_enter == this)
 2742         gApplication::_enter = NULL;
 2743 
 2744     if (!_inside)
 2745         return;
 2746 
 2747     #if DEBUG_ENTER_LEAVE
 2748     fprintf(stderr, "========== START LEAVE %s\n", name());
 2749     #endif
 2750 
 2751     if (isContainer())
 2752     {
 2753         gContainer *cont = (gContainer *)this;
 2754         int i;
 2755 
 2756         for (i = 0; i < cont->childCount(); i++)
 2757             cont->child(i)->emitLeaveEvent();
 2758     }
 2759 
 2760     _inside = false;
 2761     
 2762     #ifdef GTK3
 2763     onLeaveEvent();
 2764     #endif
 2765 
 2766     #if DEBUG_ENTER_LEAVE
 2767     fprintf(stderr, ">>>>>>>>>> END LEAVE %s\n", name());
 2768     #endif
 2769 
 2770     if (parent()) parent()->setMouse(parent()->mouse());
 2771 
 2772     if (gApplication::_ignore_until_next_enter)
 2773     {
 2774         #if DEBUG_ENTER_LEAVE
 2775         fprintf(stderr, "ignore next leave for %s\n", name());
 2776         #endif
 2777         return;
 2778     }
 2779 
 2780     //fprintf(stderr, "RAISE LEAVE: %s\n", name());
 2781     emit(SIGNAL(onEnterLeave), gEvent_Leave);
 2782 }
 2783 
 2784 bool gControl::isAncestorOf(gControl *child)
 2785 {
 2786     if (!isContainer())
 2787         return false;
 2788 
 2789     for(;;)
 2790     {
 2791         child = child->parent();
 2792         if (!child)
 2793             return false;
 2794         else if (child == this)
 2795             return true;
 2796     }
 2797 }
 2798 
 2799 #ifdef GTK3
 2800 void gControl::drawBackground(cairo_t *cr)
 2801 {
 2802     if (background() == COLOR_DEFAULT)
 2803         return;
 2804 
 2805     gt_cairo_set_source_color(cr, background());
 2806     cairo_rectangle(cr, 0, 0, width(), height());
 2807     cairo_fill(cr);
 2808 }
 2809 #else
 2810 void gControl::drawBackground(GdkEventExpose *e)
 2811 {
 2812     GtkAllocation a;
 2813 
 2814     if (background() == COLOR_DEFAULT)
 2815         return;
 2816 
 2817     cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(border));
 2818 
 2819     gdk_cairo_region(cr, e->region);
 2820     cairo_clip(cr);
 2821     gt_cairo_set_source_color(cr, background());
 2822 
 2823     gtk_widget_get_allocation(border, &a);
 2824     cairo_rectangle(cr, a.x, a.y, width(), height());
 2825     cairo_fill(cr);
 2826 
 2827     cairo_destroy(cr);
 2828 }
 2829 #endif
 2830 
 2831 #ifdef GTK3
 2832 void gControl::updateColor()
 2833 {
 2834 }
 2835 
 2836 /*void gControl::setColorNames(const char *bg_names[], const char *fg_names[])
 2837 {
 2838     _bg_name_list = bg_names;
 2839     _fg_name_list = fg_names;
 2840 
 2841     if (!bg_names)
 2842     {
 2843         _bg_name = NULL;
 2844         _fg_name = NULL;
 2845         use_base = FALSE;
 2846         return;
 2847     }
 2848 
 2849     gt_style_lookup_color(gtk_widget_get_style_context(widget), bg_names, &_bg_name, &_bg_default);
 2850     gt_style_lookup_color(gtk_widget_get_style_context(widget), fg_names, &_fg_name, &_fg_default);
 2851 }
 2852 
 2853 void gControl::setColorBase()
 2854 {
 2855     static const char *bg_names[] = { "base_color", "theme_base_color", NULL };
 2856     static const char *fg_names[] = { "text_color", "theme_text_color", NULL };
 2857     setColorNames(bg_names, fg_names);
 2858     use_base = TRUE;
 2859 }
 2860 
 2861 void gControl::setColorButton()
 2862 {
 2863     const char *bg_names[] = { "button_bg_color", "theme_button_bg_color", "theme_bg_color", NULL };
 2864     const char *fg_names[] = { "button_fg_color", "theme_button_fg_color", "theme_fg_color", NULL };
 2865     setColorNames(bg_names, fg_names);
 2866     use_base = FALSE;
 2867 }*/
 2868 #endif
 2869 
 2870 GtkIMContext *gControl::getInputMethod()
 2871 {
 2872     return _input_method;
 2873 }
 2874 
 2875 gControl *gControl::nextFocus()
 2876 {
 2877     gControl *ctrl;
 2878     gControl *next_ctrl;
 2879     
 2880     //fprintf(stderr, "next: %s\n", name());
 2881     
 2882     if (isContainer())
 2883     {
 2884         ctrl = ((gContainer *)this)->firstChild();
 2885         if (ctrl)
 2886         {
 2887             //fprintf(stderr, "==> %s\n", ctrl->name());
 2888             return ctrl;
 2889         }
 2890     }
 2891     
 2892     ctrl = this;
 2893     
 2894     for(;;)
 2895     {
 2896         next_ctrl = ctrl->next();
 2897         if (next_ctrl)
 2898             return next_ctrl;
 2899         
 2900         ctrl = ctrl->parent();
 2901         if (!ctrl)
 2902             return NULL;
 2903         /*if (!ctrl->parent())
 2904             return ctrl->nextFocus();*/
 2905     }
 2906 }
 2907 
 2908 gControl *gControl::previousFocus()
 2909 {
 2910     gControl *ctrl = previous();
 2911     
 2912     if (!ctrl)
 2913     {
 2914         if (!isTopLevel())
 2915             return parent()->previousFocus();
 2916         
 2917         ctrl = this;
 2918     }
 2919     
 2920     while (ctrl->isContainer() && ((gContainer *)ctrl)->childCount())
 2921         ctrl = ((gContainer *)ctrl)->lastChild();
 2922 
 2923     return ctrl;
 2924 }
 2925 
 2926 void gControl::createWidget()
 2927 {
 2928 #ifdef GTK3
 2929     if (_css)
 2930     {
 2931         g_object_unref(_css);
 2932         _css = NULL;
 2933     }
 2934 #endif
 2935 }
 2936 
 2937 void gControl::createBorder(GtkWidget *new_border, bool keep_widget)
 2938 {
 2939     GtkWidget *old = border;
 2940     
 2941     border = new_border;
 2942     connectBorder();
 2943     
 2944     if (keep_widget && widget)
 2945         gt_widget_reparent(widget, border);
 2946     
 2947     if (old)
 2948     {
 2949         _no_delete = true;
 2950         gtk_widget_destroy(old);
 2951         _no_delete = false;
 2952         createWidget();
 2953     }
 2954 }
 2955 
 2956 bool gControl::setInverted(bool v)
 2957 {
 2958     if (v == _inverted)
 2959         return true;
 2960     
 2961     _inverted = v;
 2962     gt_widget_set_inverted(widget, v);
 2963     return false;
 2964 }
 2965 
 2966 void gControl::checkVisibility()
 2967 {
 2968     if (_allow_show)
 2969         return;
 2970     
 2971     _allow_show = true;
 2972     setVisibility(_visible);
 2973 }