"Fossies" - the Fresh Open Source Software Archive

Member "gambas-3.16.3/gb.gtk/src/gapplication.cpp" (7 Sep 2021, 41782 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 "gapplication.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   gapplication.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 <ctype.h>
   25 #include <time.h>
   26 #include <unistd.h>
   27 
   28 #include "widgets.h"
   29 
   30 #ifndef GTK3
   31 #include "x11.h"
   32 #include "sm/sm.h"
   33 #endif
   34 
   35 #include "gapplication.h"
   36 #include "gtrayicon.h"
   37 #include "gdesktop.h"
   38 #include "gkey.h"
   39 #include "gmenu.h"
   40 #include "gdialog.h"
   41 #include "gclipboard.h"
   42 #include "gmouse.h"
   43 #include "gprinter.h"
   44 #include "gmainwindow.h"
   45 
   46 //#define DEBUG_ENTER_LEAVE 1
   47 //#define DEBUG_FIND_CONTROL 1
   48 //#define DEBUG_FOCUS 1
   49 
   50 #ifdef GTK3
   51 static GtkApplication *_app;
   52 #endif
   53 
   54 static bool _debug_keypress = false;
   55 
   56 /**************************************************************************
   57 
   58     Global event handler
   59 
   60 **************************************************************************/
   61 
   62 static bool _focus_change = false;
   63 static bool _doing_focus_change = false;
   64 
   65 static GtkWindowGroup *get_window_group(GtkWidget *widget)
   66 {
   67   GtkWidget *toplevel = NULL;
   68 
   69   if (widget)
   70     toplevel = gtk_widget_get_toplevel(widget);
   71 
   72   if (GTK_IS_WINDOW(toplevel))
   73     return gtk_window_get_group(GTK_WINDOW(toplevel));
   74   else
   75     return gtk_window_get_group(NULL);
   76 }
   77 
   78 static gControl *find_child(gControl *control, int rx, int ry, gControl *button_grab = NULL)
   79 {
   80     gContainer *cont;
   81     gControl *child;
   82     gMainWindow *window;
   83     int x, y;
   84     int cx, cy, cw, ch;
   85     #ifdef GTK3
   86     GtkAllocation a;
   87     #endif
   88 
   89     if (gApplication::_control_grab)
   90         return gApplication::_control_grab;
   91 
   92     if (button_grab)
   93     {
   94         #if DEBUG_FIND_CONTROL
   95         fprintf(stderr, "find_child -> %s (button grab)\n", button_grab->name());
   96         #endif
   97         return button_grab;
   98     }
   99 
  100     window = control->topLevel();
  101     control = window;
  102     
  103     #ifdef GTK3
  104     gtk_widget_get_allocation(window->frame, &a);
  105     //fprintf(stderr, "find_child: %d %d window: %d %d %d %d\n", rx, ry, a.x, a.y, a.width, a.height);
  106     rx -= a.x;
  107     ry -= a.y;
  108     #endif
  109 
  110     #if DEBUG_FIND_CONTROL
  111     fprintf(stderr, "find_child: [%s %p] %s (%d %d)\n", window->name(), window, control->name(), rx, ry);
  112     #endif
  113 
  114     while (control->isContainer())
  115     {
  116         control->getScreenPos(&x, &y);
  117         #ifdef GTK3
  118         if (!control->isTopLevel())
  119         {
  120             x -= a.x;
  121             y -= a.y;
  122         }
  123         #endif
  124 
  125         #if DEBUG_FIND_CONTROL
  126         fprintf(stderr, "  screen pos %s = %d %d\n", control->name(), x ,y);
  127         #endif
  128         
  129         cont = (gContainer *)control;
  130 
  131         cx = cont->clientX();
  132         cy = cont->clientY();
  133         cw = cont->clientWidth();
  134         ch = cont->clientHeight();
  135 
  136         #if DEBUG_FIND_CONTROL
  137         fprintf(stderr, "  client area of %s: %d %d %d %d\n", control->name(), cx, cy, cw, ch);
  138         #endif
  139 
  140         x = rx - x;
  141         y = ry - y;
  142         if (x < cx || y < cy || x >= (cx + cw) || y >= (cy + ch))
  143         {
  144             #if DEBUG_FIND_CONTROL
  145             fprintf(stderr, "  outside of client area of %s\n", control->name());
  146             #endif
  147             control = NULL;
  148             break;
  149         }
  150 
  151         #if DEBUG_FIND_CONTROL
  152         fprintf(stderr, "  find coord %d %d\n", x, y);
  153         #endif
  154         child = cont->find(x, y);
  155         if (!child)
  156             break;
  157 
  158         control = child;
  159     }
  160 
  161     #if DEBUG_FIND_CONTROL
  162     fprintf(stderr, "find_child -> %s\n", control ? control->name() : "NULL");
  163     #endif
  164 
  165     return control;
  166 }
  167 
  168 void gApplication::checkHoveredControl(gControl *control)
  169 {
  170     if (gApplication::_enter != control)
  171     {
  172         #if DEBUG_ENTER_LEAVE
  173         fprintf(stderr, "checkHoveredControl: %s\n", control->name());
  174         #endif
  175 
  176         gControl *leave = gApplication::_enter;
  177 
  178         while (leave && leave != control && !leave->isAncestorOf(control))
  179         {
  180             #if DEBUG_ENTER_LEAVE
  181             fprintf(stderr, "checkHoveredControl: leave: %s\n", leave->name());
  182             #endif
  183             leave->emitLeaveEvent();
  184             leave = leave->parent();
  185         }
  186 
  187         #if DEBUG_ENTER_LEAVE
  188         fprintf(stderr, "checkHoveredControl: _enter <- %s\n", control ? control->name() : "ø");
  189         #endif
  190 
  191         if (control)
  192         {
  193             #if DEBUG_ENTER_LEAVE
  194             fprintf(stderr, "checkHoveredControl: enter: %s\n", control->name());
  195             #endif
  196             control->emitEnterEvent();
  197         }
  198     }
  199 }
  200 
  201 static void gambas_handle_event(GdkEvent *event)
  202 {
  203   GtkWidget *widget;
  204     GtkWidget *current_grab;
  205   GtkWidget *grab;
  206     GtkWindowGroup *group;
  207 #ifdef GTK3
  208     GdkDevice *device;
  209 #endif
  210     gControl *control = NULL, *save_control;
  211     gControl *button_grab;
  212     int x, y, xs, ys, xc, yc;
  213     bool cancel;
  214     int type;
  215     bool handle_event = false;
  216     bool send_to_window = false;
  217 
  218     if (gApplication::_fix_printer_dialog)
  219     {
  220         widget = gtk_get_event_widget(event);
  221         if (widget)
  222         {
  223             //fprintf(stderr, "type: %s\n", G_OBJECT_TYPE_NAME(widget));
  224             if (!strcmp(G_OBJECT_TYPE_NAME(gtk_widget_get_toplevel(widget)), "GtkPrintUnixDialog"))
  225             {
  226                 if (event->type == GDK_WINDOW_STATE)
  227                 {
  228                     //fprintf(stderr, "event: GDK_WINDOW_STATE!\n");
  229                     widget = gtk_window_get_default_widget(GTK_WINDOW(gtk_widget_get_toplevel(widget)));
  230                     if (widget && GTK_IS_BUTTON(widget))
  231                     {
  232                         GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG(gtk_widget_get_toplevel(widget));
  233                         gPrinter::fixPrintDialog(dialog);
  234                         gApplication::_fix_printer_dialog = false;
  235                         //fprintf(stderr, "gtk_button_clicked: %s\n", gtk_button_get_label(GTK_BUTTON(widget)));
  236                         if (gApplication::_close_next_window)
  237                             gtk_button_clicked(GTK_BUTTON(widget));
  238                         gApplication::_close_next_window = false;
  239                         //return;
  240                         //g_timeout_add(0, (GSourceFunc)close_dialog, GTK_BUTTON(widget));
  241                         goto __HANDLE_EVENT;
  242                     }
  243                     //fprintf(stderr, "event: MAP! <<< end\n");
  244                 }
  245             }
  246         }
  247     }
  248 
  249     /*if (event->type == GDK_GRAB_BROKEN)
  250     {
  251         if (gApplication::_in_popup)
  252             fprintf(stderr, "**** GDK_GRAB_BROKEN inside popup: %s %swindow = %p grab_window = %p popup_window = %p\n", event->grab_broken.keyboard ? "keyboard" : "pointer",
  253                             event->grab_broken.implicit ? "implicit " : "", event->grab_broken.window, event->grab_broken.grab_window, gApplication::_popup_grab_window);
  254     }*/
  255 
  256     if (!((event->type >= GDK_MOTION_NOTIFY && event->type <= GDK_FOCUS_CHANGE) || event->type == GDK_SCROLL))
  257         goto __HANDLE_EVENT;
  258 
  259     widget = gtk_get_event_widget(event);
  260     if (!widget)
  261         goto __HANDLE_EVENT;
  262     
  263     if (_debug_keypress && (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE))
  264     {
  265         fprintf(stderr, "[%p] %s: keyval = %d state = %08X (%08X) is_modifier = %d hardware = %d send_event = %d for %p\n", event, event->type == GDK_KEY_PRESS ? "GDK_KEY_PRESS" : "GDK_KEY_RELEASE",
  266                         event->key.keyval, event->key.state, event->key.state & ~GDK_MODIFIER_MASK, event->key.is_modifier, event->key.hardware_keycode, event->key.send_event, widget);
  267     }
  268 
  269     /*if ((event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE))
  270     {
  271         if (event->key.state & ~GDK_MODIFIER_MASK) // == 0)
  272         {
  273             if (_debug_keypress)
  274                 fprintf(stderr, "ignore key event\n");
  275             goto __HANDLE_EVENT;
  276         }
  277     }*/
  278 
  279 #ifdef GTK3
  280     device = gdk_event_get_device (event);
  281     group = get_window_group(widget);
  282     current_grab = gtk_window_group_get_current_device_grab(group, device);
  283     if (!current_grab)
  284         current_grab = gtk_window_group_get_current_grab(group); //gtk_grab_get_current();
  285 #else
  286     group = get_window_group(widget);
  287     current_grab = gtk_window_group_get_current_grab(group); //gtk_grab_get_current();
  288 #endif
  289 
  290     button_grab = gApplication::_button_grab;
  291 
  292     if (gApplication::_control_grab)
  293     {
  294         control = gApplication::_control_grab;
  295         widget = control->border;
  296         //fprintf(stderr, "[1] _control_grab: %s -> widget = %p\n", control->name(), widget);
  297         goto __FOUND_WIDGET;
  298     }
  299 
  300     if (gMenu::currentPopup())
  301     {
  302         grab = GTK_WIDGET(gMenu::currentPopup()->_popup);
  303         //fprintf(stderr, "[2] popup menu: grab = %p\n", grab);
  304         if (get_window_group(grab) != get_window_group(widget) && (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY))
  305             goto __RETURN;
  306     }
  307     else
  308     {
  309         grab = current_grab; //gtk_window_group_get_current_grab(get_window_group(widget));
  310         //fprintf(stderr, "[3] popup: grab = %p / %p / %p\n", gApplication::_popup_grab, grab, gtk_grab_get_current());
  311         if (!grab)
  312             grab = gApplication::_popup_grab;
  313         //fprintf(stderr, "[4] grab = %p\n", grab);
  314         //fprintf(stderr, "search grab for widget %p -> group = %p -> grab = %p WINDOW = %d\n", widget, get_window_group(widget), grab, GTK_IS_WINDOW(grab));
  315         //if (grab && grab != widget && !GTK_IS_WINDOW(grab))
  316         //  goto __HANDLE_EVENT;
  317 
  318         //if (!grab && gApplication::_popup_grab)
  319         //  grab = gApplication::_popup_grab;
  320     }
  321         //gdk_window_get_user_data(gApplication::_popup_grab_window, (gpointer *)&grab);
  322 
  323     if (grab)
  324     {
  325         control = gt_get_control(grab);
  326         //fprintf(stderr, "grab = %p -> %p %s\n", grab, control, control ? control->name() : "");
  327 
  328         if (!control)
  329             goto __HANDLE_EVENT;
  330     }
  331 
  332     if (event->type == GDK_FOCUS_CHANGE)
  333     {
  334         control = NULL;
  335         //if (GTK_IS_WINDOW(widget))
  336         control = gt_get_control(widget);
  337         
  338         if (!control || control->isDesign())
  339             goto __HANDLE_EVENT;
  340         //fprintf(stderr, "GDK_FOCUS_CHANGE: widget = %p %d : %s %d\n", widget, GTK_IS_WINDOW(widget), control ? control->name() : NULL, event->focus_change.in);
  341 
  342         //if (GTK_IS_WINDOW(widget))
  343         {
  344             control = gt_get_control(widget);
  345             if (control)
  346                 gApplication::setActiveControl(control, event->focus_change.in);
  347             else if (event->focus_change.in)
  348             {
  349                 //fprintf(stderr, "GDK_FOCUS_CHANGE: setActiveWindow(NULL)\n");
  350                 gMainWindow::setActiveWindow(NULL);
  351             }
  352         }
  353 
  354         if (event->focus_change.in && grab && widget != grab && !gtk_widget_is_ancestor(widget, grab))
  355         {
  356             //fprintf(stderr, "Check popup grab\n");
  357             gApplication::grabPopup();
  358             // Must continue, otherwise things are broken by some styles
  359             //return;
  360         }
  361 
  362         goto __HANDLE_EVENT;
  363     }
  364 
  365     if (grab && widget != grab && !gtk_widget_is_ancestor(widget, grab))
  366     {
  367         //fprintf(stderr, "-> widget = grab\n");
  368         widget = grab;
  369     }
  370 
  371     //fprintf(stderr, "grab = %p widget = %p %d\n", grab, widget, grab && !gtk_widget_is_ancestor(widget, grab));
  372 
  373     while (widget)
  374     {
  375         control = gt_get_control(widget);
  376         if (control || grab)
  377             break;
  378         widget = gtk_widget_get_parent(widget);
  379     }
  380 
  381     /*if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE || event->type == GDK_MOTION_NOTIFY)
  382     {
  383         fprintf(stderr, "[%s] widget = %p grab = %p _popup_grab = %p _button_grab = %p\n",
  384                         event->type == GDK_BUTTON_PRESS ? "down" : event->type == GDK_BUTTON_RELEASE ? "up" : "move",
  385                         widget, grab, gApplication::_popup_grab, gApplication::_button_grab);
  386         //fprintf(stderr, "widget = %p (%p) grab = %p (%p)\n", widget, widget ? g_object_get_data(G_OBJECT(widget), "gambas-control") : 0,
  387         //              grab, grab ? g_object_get_data(G_OBJECT(grab), "gambas-control") : 0);
  388     }*/
  389 
  390     /*if (event->type == GDK_BUTTON_PRESS || event->type == GDK_KEY_PRESS)
  391     {
  392         fprintf(stderr, "[GDK_BUTTON_PRESS] widget = %p control = %p grab = %p _popup_grab = %p _button_grab = %p\n",
  393                         widget, control, grab, gApplication::_popup_grab, gApplication::_button_grab);
  394     }*/
  395 
  396     if (!widget || !control)
  397         goto __HANDLE_EVENT;
  398 
  399 __FOUND_WIDGET:
  400 
  401     //fprintf(stderr, "control = %p %s\n", control, control->name());
  402 
  403     /*switch ((int)event->type)
  404     {
  405         case GDK_ENTER_NOTIFY:
  406             fprintf(stderr, "ENTER: %p %s\n", control, control ? control->name() : 0);
  407             break;
  408 
  409         case GDK_LEAVE_NOTIFY:
  410             fprintf(stderr, "LEAVE: %p %s\n", control, control ? control->name() : 0);
  411             break;
  412     }*/
  413 
  414     //group = get_window_group(widget);
  415     //if (group != gApplication::currentGroup())
  416     //  goto __HANDLE_EVENT;
  417 
  418     cancel = false;
  419 
  420     gApplication::updateLastEvent(event);
  421 
  422     switch ((int)event->type)
  423     {
  424         case GDK_ENTER_NOTIFY:
  425 
  426             if (event->crossing.detail == GDK_NOTIFY_INFERIOR)
  427                 break;
  428             
  429             control = find_child(control, (int)event->crossing.x_root, (int)event->crossing.y_root);
  430             if (!control)
  431                 goto __HANDLE_EVENT;
  432 
  433 #if DEBUG_ENTER_LEAVE
  434             fprintf(stderr, "GDK_ENTER_NOTIFY: %s (%s) %d %d %p [%d] %p\n", control->name(), gApplication::_enter ? gApplication::_enter->name() : "ø", (int)event->crossing.x_root, (int)event->crossing.y_root, event->crossing.window, gdk_window_is_input_only(event->crossing.window), event->crossing.subwindow);
  435 #endif
  436 
  437             if (button_grab)
  438             {
  439                 gApplication::_enter_after_button_grab = control;
  440                 break;
  441             }
  442 
  443             if (gApplication::_leave)
  444             {
  445                 if (gApplication::_leave == control || gApplication::_leave->isAncestorOf(control))
  446                     gApplication::_leave = NULL;
  447             }
  448 
  449             gApplication::checkHoveredControl(control);
  450 
  451             /*
  452             if (gApplication::_leave == control)
  453             {
  454                 #if DEBUG_ENTER_LEAVE
  455                 fprintf(stderr, "enter ignored: %s\n", control->name());
  456                 #endif
  457                 gApplication::_leave = NULL;
  458             }
  459             else if (gApplication::_enter != control)
  460             {
  461                 if (check_crossing_event(event))
  462                 {
  463                     #if DEBUG_ENTER_LEAVE
  464                     fprintf(stderr, "enter: %s\n", control->name());
  465                     #endif
  466                     gApplication::checkHoveredControl(control);
  467                 }
  468             }*/
  469 
  470             break;
  471 
  472         case GDK_LEAVE_NOTIFY:
  473 
  474 #if DEBUG_ENTER_LEAVE
  475             fprintf(stderr, "GDK_LEAVE_NOTIFY: %s (%d %d) %p %p\n", control->name(), event->crossing.mode, event->crossing.detail, event->crossing.window, event->crossing.subwindow);
  476 #endif
  477 
  478             if (button_grab)
  479                 break;
  480 
  481             if (event->crossing.detail == GDK_NOTIFY_INFERIOR)
  482                 break;
  483             
  484             //control = find_child(control, (int)event->button.x_root, (int)event->button.y_root);
  485 
  486             gApplication::_leave = control;
  487             /*
  488             if (gdk_events_pending() && gApplication::_leave == NULL)
  489             {
  490                 if (check_crossing_event(event))
  491                 {
  492                     #if DEBUG_ENTER_LEAVE
  493                     fprintf(stderr, "leave later: %s\n", control->name());
  494                     #endif
  495                     gApplication::_leave = control;
  496                 }
  497             }
  498             else if (gApplication::_leave != control)
  499             {
  500                 if (check_crossing_event(event))
  501                 {
  502                     if (gApplication::_leave == control)
  503                         gApplication::_leave = NULL;
  504 
  505                     #if DEBUG_ENTER_LEAVE
  506                     fprintf(stderr, "leave: %s\n", control->name());
  507                     #endif
  508                     control->emitLeaveEvent();
  509                 }
  510             }
  511             */
  512 
  513             //if (widget != control->border && widget != control->widget)
  514             //  goto __RETURN;
  515 
  516             break;
  517 
  518         case GDK_BUTTON_PRESS:
  519         case GDK_2BUTTON_PRESS:
  520         case GDK_BUTTON_RELEASE:
  521         {
  522             /*if (event->type == GDK_BUTTON_PRESS)
  523                 fprintf(stderr, "GDK_BUTTON_PRESS: %p / %p / %p\n", control, button_grab, gApplication::_control_grab);*/
  524             /*else if (event->type == GDK_BUTTON_RELEASE)
  525                 fprintf(stderr, "GDK_BUTTON_RELEASE: %p / %p\n", control, button_grab);*/
  526 
  527             switch ((int)event->type)
  528             {
  529                 case GDK_BUTTON_PRESS: type = gEvent_MousePress; break;
  530                 case GDK_2BUTTON_PRESS: type = gEvent_MouseDblClick; break;
  531                 default: type = gEvent_MouseRelease; break;
  532             }
  533 
  534             save_control = find_child(control, (int)event->button.x_root, (int)event->button.y_root, button_grab);
  535             
  536             /*if (type == gEvent_MousePress)
  537                 fprintf(stderr, "save_control = %p %s\n", save_control, save_control ? save_control->name() : "");*/
  538             
  539             if (save_control)
  540                 save_control = save_control->ignoreDesign();
  541             
  542             if (!save_control)
  543             {
  544                 if (type == gEvent_MousePress && control->isTopLevel())
  545                 {
  546                     gMainWindow *win = ((gMainWindow *)control);
  547                     if (win->isPopup())
  548                         win->close();
  549                 }
  550                 
  551                 //fprintf(stderr, "handle event %s\n", type == gEvent_MousePress ? "press" : type == gEvent_MouseRelease ? "release" : "other");
  552             
  553                 goto __HANDLE_EVENT;
  554             }
  555 
  556             control = save_control;
  557 
  558 #if GTK_CHECK_VERSION(3, 4, 0)
  559             bool menu = gdk_event_triggers_context_menu(event);
  560 #else
  561             bool menu = (event->button.button == 3) && (event->type == GDK_BUTTON_PRESS);
  562 #endif
  563 
  564             if (event->type != GDK_BUTTON_RELEASE)
  565             {
  566                 #if DEBUG_FOCUS
  567                 fprintf(stderr, "GDK_BUTTON_PRESS: %s canFocus = %d design = %d\n", control->name(), control->canFocus(), control->isDesign());
  568                 #endif
  569                 if (control->canFocusOnClick())
  570                     control->setFocus();
  571                 if (!control->_no_auto_grab)
  572                     gApplication::setButtonGrab(control);
  573             }
  574 
  575             if (event->type == GDK_BUTTON_PRESS)
  576                 gMouse::handleClickCount(event);
  577 
  578         __BUTTON_TRY_PROXY:
  579         
  580             cancel = false;
  581 
  582             if (control->isDesign() || control->isEnabled())
  583             {
  584                 if (control->onMouseEvent)
  585                 {
  586                     if (event->type == GDK_BUTTON_PRESS || control->canRaise(control, type))
  587                     {
  588                         control->getScreenPos(&xc, &yc);
  589                         xs = (int)event->button.x_root;
  590                         ys = (int)event->button.y_root;
  591                         x = xs - xc;
  592                         y = ys - yc;
  593 
  594                         gMouse::validate();
  595                         gMouse::setEvent(event);
  596                         //gMouse::setValid(1,(int)event->x,(int)event->y,event->button,event->state,data->screenX(),data->screenY());
  597                         gMouse::setMouse(x, y, xs, ys, event->button.button, event->button.state);
  598                         switch ((int)event->type)
  599                         {
  600                             case GDK_BUTTON_PRESS:
  601                                 gMouse::setControl(control);
  602                                 gMouse::setStart(x, y);
  603                                 cancel = control->onMouseEvent(control, gEvent_MousePress);
  604                                 break;
  605 
  606                             case GDK_2BUTTON_PRESS:
  607                                 cancel = control->onMouseEvent(control, gEvent_MouseDblClick);
  608                                 break;
  609 
  610                             case GDK_BUTTON_RELEASE:
  611                                 gMouse::setControl(NULL);
  612                                 cancel = control->onMouseEvent(control, gEvent_MouseRelease);
  613                                 break;
  614                         }
  615 
  616                         gMouse::invalidate();
  617                     }
  618                 }
  619             }
  620 
  621             if (type == gEvent_MouseRelease && control->_grab)
  622             {
  623                 gApplication::exitLoop(control);
  624             }
  625 
  626             if (!cancel)
  627             {
  628                 if (control->_proxy_for)
  629                 {
  630                     control = control->_proxy_for;
  631                     //fprintf(stderr, "PRESS: try %s\n", control->name());
  632                     goto __BUTTON_TRY_PROXY;
  633                 }
  634             }
  635 
  636             if (menu)
  637             {
  638                 control = save_control;
  639                 while (control)
  640                 {
  641                     //fprintf(stderr, "menu %s D = %d DI = %d\n", control->name(), control->isDesign(), control->isDesignIgnore());
  642                     if (control->onMouseEvent(control, gEvent_MouseMenu))
  643                     {
  644                         cancel = true;
  645                         break;
  646                     }
  647                     if (control->hasNativePopup())
  648                         goto __HANDLE_EVENT;
  649                     
  650                     control = control->_proxy_for;
  651                 }
  652             }
  653 
  654             if (cancel)
  655             {
  656                 gMouse::resetTranslate();
  657                 goto __RETURN;
  658             }
  659 
  660             if (widget != save_control->border && widget != save_control->widget)
  661             {
  662                 //fprintf(stderr, "widget = %p, control = %p %p %s\n", widget, save_control->border, save_control->widget, save_control->name());
  663                 gMouse::resetTranslate();
  664                 goto __RETURN;
  665             }
  666 
  667             break;
  668         }
  669 
  670         case GDK_MOTION_NOTIFY:
  671 
  672             gdk_event_request_motions(&event->motion);
  673 
  674             save_control = control = find_child(control, (int)event->motion.x_root, (int)event->motion.y_root, button_grab);
  675             if (!control)
  676                 goto __HANDLE_EVENT;
  677 
  678             control = control->ignoreDesign();
  679             /*while (control->isDesignIgnore())
  680                 control = control->parent();*/
  681             //fprintf(stderr, "GDK_MOTION_NOTIFY: (%p %s) grab = %p\n", control, control->name(), button_grab);
  682 
  683             gApplication::checkHoveredControl(control);
  684 
  685         __MOTION_TRY_PROXY:
  686 
  687             if (!control->isDesign() && !control->isEnabled())
  688                 goto __HANDLE_EVENT;
  689 
  690             if (control->onMouseEvent && (control->canRaise(control, gEvent_MouseMove) || control->canRaise(control, gEvent_MouseDrag))
  691                     && (control->isTracking() || (event->motion.state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))))
  692             {
  693                 control->getScreenPos(&xc, &yc);
  694                 xs = (int)event->motion.x_root;
  695                 ys = (int)event->motion.y_root;
  696                 x = xs - xc;
  697                 y = ys - yc;
  698 
  699                 gMouse::validate();
  700                 gMouse::setEvent(event);
  701                 gMouse::setMouse(x, y, xs, ys, 0, event->motion.state);
  702 
  703                 //fprintf(stderr, "pressure = %g\n", gMouse::getAxis(GDK_AXIS_PRESSURE));
  704 
  705                 cancel = control->onMouseEvent(control, gEvent_MouseMove);
  706 
  707                 //if (data->acceptDrops() && gDrag::checkThreshold(data, gMouse::x(), gMouse::y(), gMouse::startX(), gMouse::startY()))
  708                 if (!cancel && (event->motion.state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))
  709                         //&& (abs(gMouse::x() - gMouse::y()) + abs(gMouse::startX() - gMouse::startY())) > 8)
  710                         && gDrag::checkThreshold(control, gMouse::x(), gMouse::y(), gMouse::startX(), gMouse::startY()))
  711                 {
  712                     //fprintf(stderr, "gEvent_MouseDrag: event = %p\n", gApplication::lastEvent());
  713                     cancel = control->onMouseEvent(control, gEvent_MouseDrag);
  714                 }
  715                 gMouse::invalidate();
  716 
  717                 if (cancel)
  718                     goto __RETURN;
  719             }
  720 
  721             if (control->_proxy_for)
  722             {
  723                 control = control->_proxy_for;
  724                 //fprintf(stderr, "MOVE: try %s\n", control->name());
  725                 goto __MOTION_TRY_PROXY;
  726             }
  727 
  728             gMouse::resetTranslate();
  729             //if (widget != save_control->border && widget != save_control->widget)
  730             //  goto __RETURN;
  731 
  732             break;
  733 
  734         case GDK_SCROLL:
  735 
  736             save_control = control = find_child(control, (int)event->scroll.x_root, (int)event->scroll.y_root);
  737             if (!control)
  738                 goto __HANDLE_EVENT;
  739 
  740             control = control->ignoreDesign();
  741             /*while (control->isDesignIgnore())
  742                 control = control->parent();*/
  743             
  744         __SCROLL_TRY_PROXY:
  745 
  746             if (!control->isDesign() && !control->isEnabled())
  747                 goto __HANDLE_EVENT;
  748 
  749             if (control->onMouseEvent && control->canRaise(control, gEvent_MouseWheel))
  750             {
  751                 int dir, dt, ort;
  752                 
  753                 control->setFocus();
  754 
  755                 control->getScreenPos(&xc, &yc);
  756                 xs = (int)event->scroll.x_root;
  757                 ys = (int)event->scroll.y_root;
  758                 x = xs - xc;
  759                 y = ys - yc;
  760 
  761                 dir = event->scroll.direction;
  762 
  763 #ifdef GTK3
  764                 if (dir == GDK_SCROLL_SMOOTH)
  765                 {
  766                     /*gdouble dx = 0, dy = 0;
  767                     gdk_event_get_scroll_deltas((GdkEvent *)event, &dx, &dy);
  768                     if (fabs(dy) > fabs(dx))
  769                         dir = (dy < 0) ? GDK_SCROLL_UP : GDK_SCROLL_DOWN;
  770                     else
  771                         dir = (dx < 0) ? GDK_SCROLL_LEFT : GDK_SCROLL_RIGHT;*/
  772                     goto __HANDLE_EVENT;
  773                 }
  774 #endif
  775 
  776                 switch (dir)
  777                 {
  778                     case GDK_SCROLL_DOWN: dt = -1; ort = 1; break;
  779                     case GDK_SCROLL_LEFT: dt = -1; ort = 0; break;
  780                     case GDK_SCROLL_RIGHT:  dt = 1; ort = 0; break;
  781                     case GDK_SCROLL_UP: default: dt = 1; ort = 1; break;
  782                 }
  783 
  784                 gMouse::validate();
  785                 gMouse::setEvent(event);
  786                 gMouse::setMouse(x, y, xs, ys, 0, event->scroll.state);
  787                 gMouse::setWheel(dt, ort);
  788                 cancel = control->onMouseEvent(control, gEvent_MouseWheel);
  789                 gMouse::invalidate();
  790             }
  791 
  792             if (cancel)
  793             {
  794                 gMouse::resetTranslate();
  795                 goto __RETURN;
  796             }
  797 
  798             if (control->_proxy_for)
  799             {
  800                 control = control->_proxy_for;
  801                 goto __SCROLL_TRY_PROXY;
  802             }
  803 
  804             if (!control->_use_wheel)
  805             {
  806                 control = control->parent();
  807                 if (control)
  808                     goto __SCROLL_TRY_PROXY;
  809             }
  810 
  811             if (widget != save_control->border && widget != save_control->widget)
  812             {
  813                 gMouse::resetTranslate();
  814                 goto __RETURN;
  815             }
  816 
  817             break;
  818 
  819         case GDK_KEY_PRESS:
  820 
  821             if (event->key.keyval)
  822                 gKey::_last_key_press = event->key.keyval;
  823             send_to_window = control->isTopLevel();
  824             goto __HANDLE_EVENT;
  825 
  826         case GDK_KEY_RELEASE:
  827 
  828             if (event->key.keyval)
  829                 gKey::_last_key_release = event->key.keyval;
  830             send_to_window = control->isTopLevel();
  831             goto __HANDLE_EVENT;
  832             
  833         default:
  834             
  835             handle_event = true;
  836             goto __RETURN;
  837     }
  838 
  839 __HANDLE_EVENT:
  840 
  841     handle_event = !control || !control->isDesign();
  842 
  843 __RETURN:
  844 
  845     if (event->type == GDK_BUTTON_RELEASE && gApplication::_button_grab)
  846     {
  847         if (gApplication::_enter_after_button_grab)
  848         {
  849             gApplication::checkHoveredControl(gApplication::_enter_after_button_grab);
  850             gApplication::_enter_after_button_grab = NULL;
  851         }
  852         gApplication::setButtonGrab(NULL);
  853     }
  854 
  855     if (handle_event)
  856         gtk_main_do_event(event);
  857 
  858     if (send_to_window)
  859         gcb_key_event(widget, event, control);
  860 
  861     if (!gdk_events_pending()) // && event->type != GDK_ENTER_NOTIFY && event->type != GDK_LEAVE_NOTIFY)
  862     {
  863         if (gApplication::_leave)
  864         {
  865             //if () // || (gApplication::_leave != control && check_crossing_event(event)))
  866             #if DEBUG_ENTER_LEAVE
  867             fprintf(stderr, "post leave: %s\n", gApplication::_leave->name());
  868             #endif
  869 
  870             if (gApplication::_enter == gApplication::_leave)
  871                 gApplication::_enter = NULL;
  872 
  873             gApplication::_leave->emitLeaveEvent();
  874 
  875             gApplication::_leave = NULL;
  876         }
  877     }
  878 
  879     gApplication::_event = NULL;
  880 }
  881 
  882 
  883 
  884 /**************************************************************************
  885 
  886 gApplication
  887 
  888 **************************************************************************/
  889 
  890 int appEvents;
  891 
  892 bool gApplication::_init = false;
  893 bool gApplication::_busy = false;
  894 char *gApplication::_title = NULL;
  895 char *gApplication::_theme = NULL;
  896 int gApplication::_in_popup = 0;
  897 GtkWidget *gApplication::_popup_grab = NULL;
  898 int gApplication::_loopLevel = 0;
  899 void *gApplication::_loop_owner = 0;
  900 GtkWindowGroup *gApplication::_group = NULL;
  901 gControl *gApplication::_enter = NULL;
  902 gControl *gApplication::_leave = NULL;
  903 gControl *gApplication::_ignore_until_next_enter = NULL;
  904 gControl *gApplication::_button_grab = NULL;
  905 gControl *gApplication::_enter_after_button_grab = NULL;
  906 gControl *gApplication::_control_grab = NULL;
  907 gControl *gApplication::_active_control = NULL;
  908 gControl *gApplication::_previous_control = NULL;
  909 gControl *gApplication::_old_active_control = NULL;
  910 bool (*gApplication::onKeyEvent)(int) = NULL;
  911 guint32 gApplication::_event_time = 0;
  912 bool gApplication::_close_next_window = false;
  913 bool gApplication::_fix_printer_dialog = false;
  914 gMainWindow *gApplication::_main_window = NULL;
  915 void (*gApplication::onEnterEventLoop)();
  916 void (*gApplication::onLeaveEventLoop)();
  917 bool gApplication::_must_quit = false;
  918 GdkEvent *gApplication::_event = NULL;
  919 bool gApplication::_keep_focus = false;
  920 
  921 bool gApplication::_fix_breeze = false;
  922 bool gApplication::_fix_oxygen = false;
  923 int gApplication::_scrollbar_size = 0;
  924 int gApplication::_scrollbar_big_size = 0;
  925 
  926 void gApplication::grabPopup()
  927 {
  928     //fprintf(stderr, "grabPopup: %p\n", _popup_grab);
  929 
  930     if (!_popup_grab)
  931         return;
  932 
  933     gt_grab(_popup_grab, TRUE, _event_time); //GDK_CURRENT_TIME);
  934 }
  935 
  936 void gApplication::ungrabPopup()
  937 {
  938     //fprintf(stderr, "ungrabPopup: %p\n", _popup_grab);
  939     //gtk_grab_remove(_popup_grab);
  940 
  941     if (_popup_grab)
  942     {
  943         _popup_grab = NULL;
  944         gt_ungrab();
  945     }
  946 }
  947 
  948 bool gApplication::areTooltipsEnabled()
  949 {
  950   gboolean enabled;
  951   GtkSettings *settings;
  952 
  953   settings = gtk_settings_get_default();
  954 
  955   g_object_get (settings, "gtk-enable-tooltips", &enabled, (char *)NULL);
  956 
  957   return enabled;
  958 }
  959 
  960 void gApplication::enableTooltips(bool vl)
  961 {
  962   GtkSettings *settings;
  963     gboolean enabled = vl;
  964   settings = gtk_settings_get_default();
  965   g_object_set (settings, "gtk-enable-tooltips", enabled, (char *)NULL);
  966 }
  967 
  968 static void do_nothing()
  969 {
  970 }
  971 
  972 #ifndef GTK3
  973 static gboolean master_client_save_yourself(GnomeClient *client, gint phase, GnomeSaveStyle save_style, gboolean is_shutting_down, GnomeInteractStyle interact_style, gboolean fast, gpointer user_data)
  974 {
  975     if (gApplication::mainWindow())
  976     {
  977         //fprintf(stderr, "master_client_save_yourself: %d\n", X11_window_get_desktop((Window)(gApplication::mainWindow()->handle())));
  978         session_manager_set_desktop(X11_window_get_desktop((Window)(gApplication::mainWindow()->handle())));
  979     }
  980     return true;
  981 }
  982 
  983 static void master_client_die(GnomeClient *client, gpointer user_data)
  984 {
  985     if (gApplication::mainWindow())
  986         gApplication::mainWindow()->close();
  987     else
  988         gMainWindow::closeAll();
  989 
  990     gApplication::quit();
  991     MAIN_check_quit();
  992 }
  993 #endif
  994 
  995 static void cb_theme_changed(GtkSettings *settings, GParamSpec *param, gpointer data)
  996 {
  997     gApplication::onThemeChange();
  998     gDesktop::onThemeChange();
  999 }
 1000 
 1001 void gApplication::init(int *argc, char ***argv)
 1002 {
 1003     GtkSettings *settings;
 1004     
 1005     appEvents = 0;
 1006 
 1007     #ifdef GTK3
 1008     _app = gtk_application_new(NULL, G_APPLICATION_FLAGS_NONE);
 1009     g_object_set(G_OBJECT(_app), "register-session", TRUE, NULL);
 1010     #else
 1011     session_manager_init(argc, argv);
 1012     g_signal_connect(gnome_master_client(), "save-yourself", G_CALLBACK(master_client_save_yourself), NULL);
 1013     g_signal_connect(gnome_master_client(), "die", G_CALLBACK(master_client_die), NULL);
 1014     #endif
 1015 
 1016     getStyleName();
 1017 
 1018     settings = gtk_settings_get_default();
 1019     g_signal_connect(G_OBJECT(settings), "notify::gtk-theme-name", G_CALLBACK(cb_theme_changed), 0);
 1020     
 1021     gdk_event_handler_set((GdkEventFunc)gambas_handle_event, NULL, NULL);
 1022 
 1023     gKey::init();
 1024 
 1025     onEnterEventLoop = do_nothing;
 1026     onLeaveEventLoop = do_nothing;
 1027 
 1028     _group = gtk_window_group_new();
 1029 
 1030     _loop_owner = 0;
 1031 
 1032     char *env = getenv("GB_GTK_DEBUG_KEYPRESS");
 1033     if (env && strcmp(env, "0"))
 1034         _debug_keypress = true;
 1035 
 1036 #ifdef GTK3
 1037     // Override theme
 1038     GtkCssProvider *css = gtk_css_provider_new();
 1039     gtk_css_provider_load_from_data(css, "button { min-width:0;min-height:0; } button.combo { padding-top:0;padding-bottom:0; }", -1, NULL);
 1040     gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 1041 #endif
 1042     
 1043     gApplication::_init = true;
 1044 }
 1045 
 1046 void gApplication::exit()
 1047 {
 1048     #ifdef GTK3
 1049     g_object_unref(_app);
 1050     #else
 1051     session_manager_exit();
 1052     #endif
 1053 
 1054     if (_title)
 1055         g_free(_title);
 1056     if (_theme)
 1057         g_free(_theme);
 1058 
 1059     gKey::exit();
 1060     gTrayIcon::exit();
 1061   gDesktop::exit();
 1062   gDialog::exit();
 1063   gFont::exit();
 1064   gt_exit();
 1065 }
 1066 
 1067 gControl* gApplication::controlItem(GtkWidget *wid)
 1068 {
 1069     gControl *control;
 1070 
 1071     while (wid)
 1072     {
 1073         control = gt_get_control(wid);
 1074         if (control)
 1075             return control;
 1076         wid = gtk_widget_get_parent(wid);
 1077     }
 1078 
 1079     return NULL;
 1080 }
 1081 
 1082 static void cb_update_busy(gControl *control)
 1083 {
 1084     if (control->mustUpdateCursor())
 1085         control->setMouse(control->mouse());
 1086 }
 1087 
 1088 void gApplication::setBusy(bool b)
 1089 {
 1090     if (b == _busy)
 1091         return;
 1092 
 1093     _busy = b;
 1094 
 1095     forEachControl(cb_update_busy);
 1096     
 1097     gdk_display_flush(gdk_display_get_default());
 1098 }
 1099 
 1100 #if 0
 1101 static bool _dirty = false;
 1102 
 1103 static gboolean update_geometry(void *data)
 1104 {
 1105     GList *iter;
 1106     gControl *control;
 1107 
 1108     if (gContainer::_arrangement_level)
 1109         return true;
 1110 
 1111     _dirty = false;
 1112     //g_debug(">>>> update_geometry");
 1113     iter = g_list_first(gControl::controlList());
 1114     while (iter)
 1115     {
 1116         control = (gControl *)iter->data;
 1117         control->updateGeometry();
 1118         iter = iter->next;
 1119     }
 1120     //g_debug("<<<<");
 1121 
 1122     return false;
 1123 }
 1124 
 1125 void gApplication::setDirty()
 1126 {
 1127     if (_dirty)
 1128         return;
 1129 
 1130     _dirty = true;
 1131     g_timeout_add(0, (GSourceFunc)update_geometry, NULL);
 1132 }
 1133 #endif
 1134 
 1135 void gApplication::setDefaultTitle(const char *title)
 1136 {
 1137     if (_title)
 1138         g_free(_title);
 1139     _title = g_strdup(title);
 1140 }
 1141 
 1142 GtkWindowGroup *gApplication::enterGroup()
 1143 {
 1144     gControl *control = _enter;
 1145     GtkWindowGroup *oldGroup = _group;
 1146     _group = gtk_window_group_new();
 1147 
 1148     _enter = _leave = NULL;
 1149 
 1150     while (control)
 1151     {
 1152         control->emit(SIGNAL(control->onEnterLeave), gEvent_Leave);
 1153         control = control->parent();
 1154     }
 1155 
 1156     return oldGroup;
 1157 }
 1158 
 1159 void gApplication::exitGroup(GtkWindowGroup *oldGroup)
 1160 {
 1161     g_object_unref(_group);
 1162     _group = oldGroup;
 1163 }
 1164 
 1165 void gApplication::enterLoop(void *owner, bool showIt, GtkWindow *modal)
 1166 {
 1167     void *old_owner = _loop_owner;
 1168     int l = _loopLevel;
 1169     //GtkWindowGroup *oldGroup;
 1170 
 1171     if (showIt) ((gControl *)owner)->show();
 1172 
 1173     //oldGroup = enterGroup();
 1174 
 1175     _loopLevel++;
 1176     _loop_owner = owner;
 1177     setButtonGrab(NULL);
 1178 
 1179     (*onEnterEventLoop)();
 1180     do
 1181     {
 1182         MAIN_do_iteration(false);
 1183     }
 1184     while (_loopLevel > l);
 1185     (*onLeaveEventLoop)();
 1186 
 1187     _loop_owner = old_owner;
 1188 
 1189     //exitGroup(oldGroup);
 1190 }
 1191 
 1192 void gApplication::enterPopup(gMainWindow *owner)
 1193 {
 1194     void *old_owner;
 1195     int l;
 1196     //GtkWindowGroup *oldGroup;
 1197     GtkWindow *window = GTK_WINDOW(owner->border);
 1198     GtkWidget *old_popup_grab;
 1199 
 1200     _in_popup++;
 1201 
 1202     // Remove possible current button grab
 1203     gApplication::setButtonGrab(NULL);
 1204 //
 1205     //oldGroup = enterGroup();
 1206 
 1207     gtk_window_set_modal(window, true);
 1208     owner->show();
 1209     gdk_window_set_override_redirect(gtk_widget_get_window(owner->border), true);
 1210     
 1211     if (!owner->isDestroyed())
 1212     {
 1213         old_popup_grab = _popup_grab;
 1214         _popup_grab = owner->border;
 1215 
 1216         if (_in_popup == 1)
 1217             owner->_grab_on_show = TRUE;
 1218             //gApplication::grabPopup();
 1219 
 1220         l = _loopLevel;
 1221         old_owner = _loop_owner;
 1222 
 1223         _loopLevel++;
 1224         _loop_owner = owner;
 1225 
 1226         (*onEnterEventLoop)();
 1227         do
 1228         {
 1229             MAIN_do_iteration(false);
 1230         }
 1231         while (_loopLevel > l);
 1232         (*onLeaveEventLoop)();
 1233 
 1234         if (_in_popup == 1)
 1235         {
 1236             if (owner->_grab_on_show)
 1237                 owner->_grab_on_show = FALSE;
 1238             else
 1239                 gApplication::ungrabPopup();
 1240         }
 1241         
 1242         _popup_grab = old_popup_grab;
 1243 
 1244         _loop_owner = old_owner;
 1245 
 1246         if (owner->border)
 1247         {
 1248             gdk_window_set_override_redirect(gtk_widget_get_window(owner->border), false);
 1249             gtk_window_set_modal(window, false);
 1250         }
 1251         //exitGroup(oldGroup);
 1252     }
 1253     else
 1254         gControl::postDelete();
 1255 
 1256     _in_popup--;
 1257 }
 1258 
 1259 void gApplication::exitLoop(void *owner)
 1260 {
 1261     if (!hasLoop(owner))
 1262         return;
 1263 
 1264     if (_loopLevel > 0)
 1265         _loopLevel--;
 1266 }
 1267 
 1268 GtkWindowGroup *gApplication::currentGroup()
 1269 {
 1270     if (_group)
 1271         return _group;
 1272     else
 1273         return gtk_window_get_group(NULL);
 1274 }
 1275 
 1276 void gApplication::updateLastEvent(GdkEvent *e)
 1277 {
 1278     _event = e;
 1279     _event_time = gdk_event_get_time(e);
 1280 }
 1281 
 1282 void gApplication::updateLastEventTime()
 1283 {
 1284     _event_time = gtk_get_current_event_time();
 1285 }
 1286 
 1287 static void post_focus_change(void *)
 1288 {
 1289     gControl *current, *control, *next;
 1290 
 1291     if (!_focus_change || _doing_focus_change)
 1292         return;
 1293 
 1294     #if DEBUG_FOCUS
 1295     fprintf(stderr, "post_focus_change: %s -> %s\n", gApplication::_old_active_control ? gApplication::_old_active_control->name() : "nil", gApplication::_active_control ? gApplication::_active_control->name() : "nil");
 1296     #endif
 1297     
 1298     _doing_focus_change = true;
 1299 
 1300     for(;;)
 1301     {
 1302         current = gApplication::activeControl();
 1303         if (current == gApplication::_old_active_control)
 1304             break;
 1305 
 1306         control = gApplication::_old_active_control;
 1307         while (control)
 1308         {
 1309             next = control->_proxy_for;
 1310             #if DEBUG_FOCUS
 1311             fprintf(stderr, "focus out %s\n", control->name());
 1312             #endif
 1313             if (control->onFocusEvent)
 1314                 control->onFocusEvent(control, gEvent_FocusOut);
 1315             control = next;
 1316         }
 1317 
 1318         current = gApplication::activeControl();
 1319         if (current == gApplication::_old_active_control)
 1320             break;
 1321 
 1322         gApplication::_old_active_control = current;
 1323         gMainWindow::setActiveWindow(current);
 1324 
 1325         control = gApplication::activeControl();
 1326         while (control)
 1327         {
 1328             next = control->_proxy_for;
 1329             #if DEBUG_FOCUS
 1330             fprintf(stderr, "focus in %s / %p\n", control->name(), control->onFocusEvent);
 1331             #endif
 1332             if (control->onFocusEvent)
 1333                 control->onFocusEvent(control, gEvent_FocusIn);
 1334             control = next;
 1335         }
 1336     }
 1337 
 1338     _doing_focus_change = false;
 1339     _focus_change = false;
 1340 }
 1341 
 1342 void gApplication::handleFocusNow()
 1343 {
 1344     post_focus_change(NULL);
 1345 }
 1346 
 1347 static void handle_focus_change()
 1348 {
 1349     if (_focus_change)
 1350         return;
 1351 
 1352     _focus_change = true;
 1353     GB.Post((void (*)())post_focus_change, (intptr_t)NULL);
 1354 }
 1355 
 1356 void gApplication::setActiveControl(gControl *control, bool on)
 1357 {
 1358     while (!control->canFocus())
 1359     {
 1360         control = control->parent();
 1361         if (!control)
 1362             return;
 1363     }
 1364     
 1365     if (on == (_active_control == control))
 1366         return;
 1367 
 1368     #if DEBUG_FOCUS
 1369     fprintf(stderr, "setActiveControl: %s %d\n", control->name(), on);
 1370     #endif
 1371     
 1372     if (_active_control && !_focus_change)
 1373         _previous_control = _active_control;
 1374 
 1375     _active_control = on ? control : NULL;
 1376     gKey::setActiveControl(_active_control);
 1377     handle_focus_change();
 1378 }
 1379 
 1380 int gApplication::getScrollbarSize()
 1381 {
 1382     if (g_type_from_name("OsBar"))
 1383     {
 1384         char *env = getenv("LIBOVERLAY_SCROLLBAR");
 1385         if (!env || *env != '0')
 1386             return 1;
 1387     }
 1388 
 1389 #ifdef GTK3
 1390 
 1391     if (_scrollbar_size == 0)
 1392     {
 1393         GtkWidget *widget = 
 1394         #ifdef GTK3
 1395             gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, NULL);
 1396         #else
 1397             gtk_hscrollbar_new(NULL);
 1398         #endif
 1399         gtk_widget_show(widget);
 1400         gtk_widget_get_preferred_width(widget, NULL, &_scrollbar_size); //, &minimum_size, &natural_size);
 1401         gtk_widget_get_preferred_height(widget, NULL, &_scrollbar_big_size); //, &minimum_size, &natural_size);
 1402         gtk_widget_destroy(widget);
 1403         
 1404         if (_fix_breeze)
 1405             _scrollbar_size += 3;
 1406         //fprintf(stderr, "getScrollbarSize = %d\n", size);
 1407     }
 1408     
 1409     return _scrollbar_size;
 1410     
 1411 #else
 1412     
 1413     gint trough_border;
 1414     gint slider_width;
 1415 
 1416     gt_get_style_property(GTK_TYPE_SCROLLBAR, "slider-width", &slider_width);
 1417     gt_get_style_property(GTK_TYPE_SCROLLBAR, "trough-border", &trough_border);
 1418 
 1419     return (trough_border) * 2 + slider_width;
 1420     
 1421 #endif
 1422 }
 1423 
 1424 int gApplication::getScrollbarBigSize()
 1425 {
 1426 #ifdef GTK3
 1427     getScrollbarSize();
 1428     return _scrollbar_big_size;
 1429 #else
 1430     return getScrollbarSize();
 1431 #endif
 1432 }
 1433 
 1434 int gApplication::getScrollbarSpacing()
 1435 {
 1436     gint v;
 1437 
 1438     gt_get_style_property(GTK_TYPE_SCROLLED_WINDOW, "scrollbar-spacing", &v);
 1439 
 1440     return v;
 1441 }
 1442 
 1443 int gApplication::getInnerWidth()
 1444 {
 1445     if (_fix_oxygen)
 1446         return 1;
 1447     else
 1448         return 0;
 1449 }
 1450 
 1451 int gApplication::getFrameWidth()
 1452 {
 1453     int w;
 1454 #ifdef GTK3
 1455     int h;
 1456 
 1457     getBoxFrame(&w, &h);
 1458     w = h;
 1459 
 1460 #else
 1461     GtkStyle *style;
 1462     gint focus_width;
 1463     gboolean interior_focus;
 1464     //int inner;
 1465 
 1466     style = gt_get_style(GTK_TYPE_ENTRY);
 1467 
 1468     gt_get_style_property(GTK_TYPE_ENTRY, "focus-line-width", &focus_width);
 1469     gt_get_style_property(GTK_TYPE_ENTRY, "interior-focus", &interior_focus);
 1470 
 1471     w = MIN(style->xthickness, style->ythickness);
 1472 
 1473     if (!interior_focus)
 1474         w += focus_width;
 1475 
 1476     w += getInnerWidth();
 1477 #endif
 1478 
 1479     return w;
 1480 }
 1481 
 1482 void gApplication::getBoxFrame(int *pw, int *ph)
 1483 {
 1484     int w, h;
 1485 
 1486 #ifdef GTK3
 1487 
 1488     GtkStyleContext *context = gt_get_style(GTK_TYPE_ENTRY);
 1489   GtkBorder border;
 1490     GtkBorder padding;
 1491     int radius;
 1492 
 1493     gtk_style_context_get_padding(context, STATE_FOCUSED, &padding);
 1494     //fprintf(stderr, "padding: %d %d %d %d\n", padding.top, padding.right, padding.bottom, padding.left);
 1495     gtk_style_context_get_border(context, STATE_FOCUSED, &border);
 1496     //fprintf(stderr, "border: %d %d %d %d\n", border.top, border.right, border.bottom, border.left);
 1497 
 1498   gtk_style_context_get(context, STATE_FOCUSED, GTK_STYLE_PROPERTY_BORDER_RADIUS, &radius, NULL);
 1499     //fprintf(stderr, "border-radius: %d\n", radius);
 1500     radius /= 2;
 1501 
 1502     w = MAX(border.left + padding.left, border.right + padding.right);
 1503     w = MAX(w, radius);
 1504 
 1505     h = MAX(border.top + padding.top, border.bottom + padding.bottom);//, MAX(padding.top, padding.bottom));
 1506     h = MAX(h, radius);
 1507 
 1508     w = MAX(2, w);
 1509     h = MAX(2, h);
 1510 
 1511 #else
 1512 
 1513     GtkStyle *style;
 1514     gint focus_width;
 1515     gboolean interior_focus;
 1516     int inner;
 1517 
 1518     style = gt_get_style(GTK_TYPE_ENTRY);
 1519 
 1520     gt_get_style_property(GTK_TYPE_ENTRY, "focus-line-width", &focus_width);
 1521     gt_get_style_property(GTK_TYPE_ENTRY, "interior-focus", &interior_focus);
 1522 
 1523     w = style->xthickness;
 1524     h = style->ythickness;
 1525 
 1526     if (!interior_focus)
 1527     {
 1528         w += focus_width;
 1529         h += focus_width;
 1530     }
 1531 
 1532     inner = getInnerWidth();
 1533     w += inner;
 1534     h += inner;
 1535 
 1536 #endif
 1537 
 1538     *pw = w;
 1539     *ph = h;
 1540 }
 1541 
 1542 char *gApplication::getStyleName()
 1543 {
 1544     if (!_theme)
 1545     {
 1546         char *p;
 1547         GtkSettings *settings = gtk_settings_get_default();
 1548         g_object_get(settings, "gtk-theme-name", &_theme, (char *)NULL);
 1549 
 1550         p = _theme = g_strdup(_theme);
 1551         while (*p)
 1552         {
 1553             *p = tolower(*p);
 1554             p++;
 1555         }
 1556         
 1557         _fix_breeze = false;
 1558         _fix_oxygen = false;
 1559         if (strcasecmp(_theme, "breeze") == 0 || strcasecmp(_theme, "breeze dark") == 0)
 1560             _fix_breeze = true;
 1561         else if (strcasecmp(_theme, "oxygen-gtk") == 0)
 1562             _fix_oxygen = true;
 1563     }
 1564 
 1565     return _theme;
 1566 }
 1567 
 1568 #ifndef GTK3
 1569 static GdkFilterReturn x11_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer data)
 1570 {
 1571     ((X11_EVENT_FILTER)data)((XEvent *)xevent);
 1572     return GDK_FILTER_CONTINUE;
 1573 }
 1574 
 1575 void gApplication::setEventFilter(X11_EVENT_FILTER filter)
 1576 {
 1577     static X11_EVENT_FILTER save_filter = NULL;
 1578     static GdkEventMask save_mask = (GdkEventMask)0;
 1579 
 1580     if (save_filter)
 1581     {
 1582         gdk_window_remove_filter(NULL, (GdkFilterFunc)x11_event_filter, (gpointer)save_filter);
 1583         gdk_window_set_events(gdk_get_default_root_window(), save_mask);
 1584     }
 1585 
 1586     if (filter)
 1587     {
 1588         save_mask = gdk_window_get_events(gdk_get_default_root_window());
 1589         gdk_window_set_events(gdk_get_default_root_window(), (GdkEventMask)(save_mask | GDK_PROPERTY_CHANGE_MASK | GDK_STRUCTURE_MASK));
 1590         gdk_window_add_filter(NULL, (GdkFilterFunc)x11_event_filter, (gpointer)filter);
 1591     }
 1592 
 1593     save_filter = filter;
 1594 }
 1595 #endif
 1596 
 1597 void gApplication::setMainWindow(gMainWindow *win)
 1598 {
 1599     _main_window = win;
 1600 }
 1601 
 1602 void gApplication::quit()
 1603 {
 1604     _must_quit = true;
 1605 }
 1606 
 1607 int gApplication::dblClickTime()
 1608 {
 1609   gint value;
 1610   g_object_get (gtk_settings_get_default(), "gtk-double-click-time", &value, (char *)NULL);
 1611     return value;
 1612 }
 1613 
 1614 void gApplication::onThemeChange()
 1615 {
 1616     if (_theme)
 1617     {
 1618         g_free(_theme);
 1619         _theme = NULL;
 1620     }
 1621     
 1622     getStyleName();
 1623     _scrollbar_size = 0;
 1624 }
 1625 
 1626 static void for_each_filter(gContainer *cont, GPtrArray *list, bool (*filter)(gControl *))
 1627 {
 1628     int i;
 1629     gControl *control;
 1630     
 1631     if ((*filter)(cont))
 1632         g_ptr_array_add(list, cont);
 1633     
 1634     for (i = 0; i < cont->childCount(); i++)
 1635     {
 1636         control = cont->child(i);
 1637         if (control->isContainer())
 1638             for_each_filter((gContainer *)control, list, filter);
 1639         else
 1640         {
 1641             if ((*filter)(control))
 1642                 g_ptr_array_add(list, control);
 1643         }
 1644     }
 1645 }
 1646 
 1647 static void for_each_control(gContainer *cont, void (*cb)(gControl *))
 1648 {
 1649     //GPtrArray *children;
 1650     int i;
 1651     gControl *control;
 1652     
 1653     (*cb)(cont);
 1654     
 1655     //children = cont->childrenCopy();
 1656     //for (i = 0; i < children->len; i++)
 1657     //{
 1658     //  control = (gControl *)g_ptr_array_index(children, i);
 1659     for (i = 0; i < cont->childCount(); i++)
 1660     {
 1661         control = cont->child(i);
 1662         
 1663         if (control->isContainer())
 1664             for_each_control((gContainer *)control, cb);
 1665         else
 1666             (*cb)(control);
 1667     }
 1668     //g_ptr_array_unref(children);
 1669 }
 1670 
 1671 // Of the callback may destroy controls, the filter must be specified!
 1672 
 1673 void gApplication::forEachControl(void (*cb)(gControl *), bool (*filter)(gControl *))
 1674 {
 1675     GList *iter_win;
 1676     gMainWindow *win;
 1677     
 1678     iter_win = g_list_first(gMainWindow::windows);
 1679     while (iter_win)
 1680     {
 1681         win = (gMainWindow *)iter_win->data;
 1682         iter_win = g_list_next(iter_win);
 1683         
 1684         if (filter)
 1685         {
 1686             uint i;
 1687             gControl *control;
 1688             GPtrArray *list = g_ptr_array_new();
 1689             
 1690             for_each_filter(win, list, filter);
 1691             
 1692             for (i = 0; i < list->len; i++)
 1693             {
 1694                 control = (gControl *)g_ptr_array_index(list, i);
 1695                 if (control->isDestroyed())
 1696                     continue;
 1697                 //fprintf(stderr, "[%d] %s\n", i, control->name());
 1698                 (*cb)(control);
 1699             }
 1700             
 1701             g_ptr_array_unref(list);
 1702         }
 1703         else
 1704         {
 1705             for_each_control(win, cb);
 1706         }
 1707     }
 1708 }