tImproved handling of keyboard focus in Win32 client - vaccinewars - be a doctor and try to vaccinate the world
 (HTM) git clone git://src.adamsgaard.dk/vaccinewars
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 7cef0a26da1a6945e69f3cb16466782112d01378
 (DIR) parent d84f46d131db94637615682f63fd7fa2b3a1ea62
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Fri, 15 Dec 2000 20:25:35 +0000
       
       Improved handling of keyboard focus in Win32 client
       
       
       Diffstat:
         M src/gtk.c                           |     136 +++++++++++++++++++++++++++++--
         M src/gtk.h                           |       5 +++++
       
       2 files changed, 135 insertions(+), 6 deletions(-)
       ---
 (DIR) diff --git a/src/gtk.c b/src/gtk.c
       t@@ -163,6 +163,10 @@ static void gtk_clist_update_all_widths(GtkCList *clist);
        static void gtk_clist_do_auto_resize(GtkCList *clist);
        static void gtk_clist_set_column_width_full(GtkCList *clist,gint column,
                                                    gint width,gboolean ResizeHeader);
       +static void gtk_widget_set_focus(GtkWidget *widget);
       +static void gtk_widget_lose_focus(GtkWidget *widget);
       +static void gtk_window_update_focus(GtkWindow *window);
       +static void gtk_window_set_focus(GtkWindow *window);
        
        typedef struct _GdkInput GdkInput;
        
       t@@ -627,6 +631,24 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,UINT wParam,LONG lParam) {
                 alloc.height=rect.bottom-rect.top;
                 gtk_widget_set_size(window,&alloc);
                 break;
       +      case WM_ACTIVATE:
       +      case WM_ACTIVATEAPP:
       +         widget=GTK_WIDGET(GetWindowLong(hwnd,GWL_USERDATA));
       +         if (widget) klass=GTK_OBJECT(widget)->klass; else klass=NULL;
       +         if (klass==&GtkWindowClass) {
       +             if ((msg==WM_ACTIVATE && LOWORD(wParam)!=WA_INACTIVE)||
       +                 (msg==WM_ACTIVATEAPP && wParam)) {
       +               if (GTK_WINDOW(widget)->focus) {
       +                  gtk_widget_set_focus(GTK_WINDOW(widget)->focus);
       +               }
       +               if (!GTK_WINDOW(widget)->focus) {
       +                  gtk_window_set_focus(GTK_WINDOW(widget));
       +               }
       +            } else if (msg==WM_ACTIVATE && LOWORD(wParam)==WA_INACTIVE) {
       +               gtk_window_update_focus(GTK_WINDOW(widget));
       +            }
       +         }
       +         break;
              case WM_COMMAND:
                 widget=GTK_WIDGET(GetWindowLong((HWND)lParam,GWL_USERDATA));
                 if (widget) klass=GTK_OBJECT(widget)->klass; else klass=NULL;
       t@@ -761,6 +783,7 @@ void gtk_widget_show_full(GtkWidget *widget,gboolean recurse) {
        
           if (GTK_WIDGET_VISIBLE(widget)) return;
           GTK_WIDGET_SET_FLAGS(widget,GTK_VISIBLE);
       +
           if (recurse) gtk_widget_show_all_full(widget,TRUE);
           else gtk_signal_emit(GTK_OBJECT(widget),"show");
        
       t@@ -777,6 +800,9 @@ void gtk_widget_show_full(GtkWidget *widget,gboolean recurse) {
              gtk_widget_update(widget,TRUE);
              if (!recurse) ShowWindow(widget->hWnd,SW_SHOWNORMAL);
           }
       +
       +// g_print("widget show - set focus\n");
       +   gtk_widget_set_focus(widget);
        }
        
        void gtk_widget_hide(GtkWidget *widget) {
       t@@ -790,6 +816,8 @@ void gtk_widget_hide_full(GtkWidget *widget,gboolean recurse) {
        
           if (!GTK_WIDGET_VISIBLE(widget)) return;
        
       +   gtk_widget_lose_focus(widget);
       +
           if (recurse) gtk_widget_hide_all_full(widget,TRUE);
           else {
              gtk_signal_emit(GTK_OBJECT(widget),"hide");
       t@@ -815,6 +843,70 @@ void gtk_widget_hide_full(GtkWidget *widget,gboolean recurse) {
           }
        }
        
       +void gtk_widget_set_focus(GtkWidget *widget) {
       +   GtkWidget *window;
       +   if (!widget || !GTK_WIDGET_CAN_FOCUS(widget) ||
       +       !GTK_WIDGET_SENSITIVE(widget) || !GTK_WIDGET_VISIBLE(widget)) return;
       +   window=gtk_widget_get_ancestor(widget,GTK_TYPE_WINDOW);
       +   gtk_window_update_focus(GTK_WINDOW(window));
       +   if (!window || GTK_WINDOW(window)->focus) return;
       +
       +// g_print("Window %p focus set to widget %p (%s)\n",window,widget,GTK_OBJECT(widget)->klass->Name);
       +   GTK_WINDOW(window)->focus=widget;
       +   if (widget->hWnd) {
       +//    if (!SetFocus(widget->hWnd)) g_print("SetFocus failed on widget %p\n",widget);
       +      SetFocus(widget->hWnd);
       +   }
       +// else g_print("Cannot call SetFocus - no hWnd\n");
       +}
       +
       +static BOOL CALLBACK SetFocusEnum(HWND hWnd,LPARAM data) {
       +   GtkWidget *widget;
       +   GtkWindow *window=GTK_WINDOW(data);
       +   widget=GTK_WIDGET(GetWindowLong(hWnd,GWL_USERDATA));
       +   if (!widget || !GTK_WIDGET_CAN_FOCUS(widget) ||
       +       !GTK_WIDGET_SENSITIVE(widget) || !GTK_WIDGET_VISIBLE(widget) ||
       +       window->focus==widget) {
       +      return TRUE;
       +   } else {
       +//g_print("gtk_window_set_focus: focus set to widget %p\n",widget);
       +      window->focus=widget;
       +      SetFocus(widget->hWnd);
       +      return FALSE;
       +   }
       +}
       +
       +void gtk_window_set_focus(GtkWindow *window) {
       +   if (!window||!GTK_WIDGET(window)->hWnd) return;
       +   EnumChildWindows(GTK_WIDGET(window)->hWnd,SetFocusEnum,(LPARAM)window);
       +}
       +
       +void gtk_widget_lose_focus(GtkWidget *widget) {
       +   GtkWidget *window;
       +   if (!widget || !GTK_WIDGET_CAN_FOCUS(widget) ||
       +       !GTK_WIDGET_SENSITIVE(widget) || !GTK_WIDGET_VISIBLE(widget)) return;
       +   window=gtk_widget_get_ancestor(widget,GTK_TYPE_WINDOW);
       +   gtk_window_update_focus(GTK_WINDOW(window));
       +   if (GTK_WINDOW(window)->focus==widget) {
       +      gtk_window_set_focus(GTK_WINDOW(window));
       +   }
       +}
       +
       +void gtk_window_update_focus(GtkWindow *window) {
       +   GtkWidget *widget;
       +   HWND FocusWnd;
       +   if (GTK_WIDGET(window)->hWnd != GetActiveWindow()) return;
       +   FocusWnd=GetFocus();
       +   window->focus=NULL;
       +   if (FocusWnd) {
       +      widget=GTK_WIDGET(GetWindowLong(FocusWnd,GWL_USERDATA));
       +      if (widget && GTK_WIDGET(window)->hWnd &&
       +          GetParent(FocusWnd)==GTK_WIDGET(window)->hWnd) {
       +         window->focus=widget;
       +      } /*else g_print("Widget %p is not child of window %p\n",widget,window);*/
       +   }// else g_print("GetFocus returned NULL\n");
       +}
       +
        void gtk_widget_realize(GtkWidget *widget) {
           GtkRequisition req;
        /* g_print("Realizing widget %p of class %s\n",widget,GTK_OBJECT(widget)->klass->Name);*/
       t@@ -822,6 +914,7 @@ void gtk_widget_realize(GtkWidget *widget) {
           if (widget->hWnd) SetWindowLong(widget->hWnd,GWL_USERDATA,(LONG)widget);
           GTK_WIDGET_SET_FLAGS(widget,GTK_REALIZED);
           gtk_widget_set_sensitive(widget,GTK_WIDGET_SENSITIVE(widget));
       +
           gtk_widget_size_request(widget,&req);
        }
        
       t@@ -831,6 +924,7 @@ void gtk_widget_create(GtkWidget *widget) {
        
        void gtk_widget_destroy(GtkWidget *widget) {
           if (!widget) return;
       +   gtk_widget_lose_focus(widget);
        // g_print("gtk_widget_destroy on widget %p\n",widget);
           gtk_signal_emit(GTK_OBJECT(widget),"destroy");
        // g_print("Freeing widget\n");
       t@@ -839,10 +933,17 @@ void gtk_widget_destroy(GtkWidget *widget) {
        }
        
        void gtk_widget_set_sensitive(GtkWidget *widget,gboolean sensitive) {
       -   if (widget->hWnd) EnableWindow(widget->hWnd,sensitive);
       +   if (sensitive) {
       +      GTK_WIDGET_SET_FLAGS(widget,GTK_SENSITIVE);
       +      if (widget->hWnd) EnableWindow(widget->hWnd,sensitive);
       +      gtk_widget_set_focus(widget);
       +   } else {
       +      gtk_widget_lose_focus(widget);
       +      GTK_WIDGET_UNSET_FLAGS(widget,GTK_SENSITIVE);
       +      if (widget->hWnd) EnableWindow(widget->hWnd,sensitive);
       +   }
       +
           gtk_signal_emit(GTK_OBJECT(widget),sensitive ? "enable" : "disable");
       -   if (sensitive) GTK_WIDGET_SET_FLAGS(widget,GTK_SENSITIVE);
       -   else GTK_WIDGET_UNSET_FLAGS(widget,GTK_SENSITIVE);
           if (sensitive && widget->hWnd && GTK_OBJECT(widget)->klass==&GtkWindowClass)
              SetActiveWindow(widget->hWnd);
        }
       t@@ -1561,7 +1662,7 @@ void gtk_window_realize(GtkWidget *widget) {
           widget->hWnd = CreateWindow("mainwin",win->title,
                             win->type == GTK_WINDOW_TOPLEVEL ?
                                WS_OVERLAPPEDWINDOW|CS_HREDRAW|CS_VREDRAW|WS_SIZEBOX :
       -                        WS_CAPTION|WS_SYSMENU|CS_HREDRAW|CS_VREDRAW,
       +                        WS_CAPTION|WS_SYSMENU|CS_HREDRAW|CS_VREDRAW|WS_SIZEBOX,
                             CW_USEDEFAULT,0,
                             widget->allocation.width,widget->allocation.height,
                             Parent,NULL,hInst,NULL);
       t@@ -1570,6 +1671,7 @@ void gtk_window_realize(GtkWidget *widget) {
           gtk_set_default_font(widget->hWnd);
        /* g_print("Window window %p created\n",widget->hWnd);*/
           gtk_container_realize(widget);
       +// if (win->focus && win->focus->hWnd) SetFocus(win->focus->hWnd);
        }
        
        void gtk_container_realize(GtkWidget *widget) {
       t@@ -1602,6 +1704,7 @@ HWND gtk_get_parent_hwnd(GtkWidget *widget) {
        void gtk_button_realize(GtkWidget *widget) {
           GtkButton *but=GTK_BUTTON(widget);
           HWND Parent;
       +   GTK_WIDGET_SET_FLAGS(widget,GTK_CAN_FOCUS);
           Parent=gtk_get_parent_hwnd(widget);
           widget->hWnd = CreateWindow("BUTTON",but->text,
                                    WS_CHILD|WS_TABSTOP|BS_PUSHBUTTON,
       t@@ -1614,6 +1717,7 @@ void gtk_button_realize(GtkWidget *widget) {
        void gtk_entry_realize(GtkWidget *widget) {
           HWND Parent;
           Parent=gtk_get_parent_hwnd(widget);
       +   GTK_WIDGET_SET_FLAGS(widget,GTK_CAN_FOCUS);
           widget->hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT","",
                                    WS_CHILD|WS_TABSTOP|ES_AUTOHSCROLL,
                                    widget->allocation.x,widget->allocation.y,
       t@@ -1629,6 +1733,7 @@ void gtk_entry_realize(GtkWidget *widget) {
        void gtk_text_realize(GtkWidget *widget) {
           HWND Parent;
           Parent=gtk_get_parent_hwnd(widget);
       +   GTK_WIDGET_SET_FLAGS(widget,GTK_CAN_FOCUS);
           widget->hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT","",
                                    WS_CHILD|WS_TABSTOP|
                                    ES_MULTILINE|ES_WANTRETURN|WS_VSCROLL|
       t@@ -1660,6 +1765,7 @@ void gtk_check_button_realize(GtkWidget *widget) {
           HWND Parent;
           gboolean toggled;
           Parent=gtk_get_parent_hwnd(widget);
       +   GTK_WIDGET_SET_FLAGS(widget,GTK_CAN_FOCUS);
           widget->hWnd = CreateWindow("BUTTON",but->text,
                                    WS_CHILD|WS_TABSTOP|BS_CHECKBOX,
                                    widget->allocation.x,widget->allocation.y,
       t@@ -1680,6 +1786,7 @@ void gtk_radio_button_realize(GtkWidget *widget) {
           HWND Parent;
           gboolean toggled;
           Parent=gtk_get_parent_hwnd(widget);
       +   GTK_WIDGET_SET_FLAGS(widget,GTK_CAN_FOCUS);
           widget->hWnd = CreateWindow("BUTTON",but->text,
                                    WS_CHILD|WS_TABSTOP|BS_RADIOBUTTON,
                                    widget->allocation.x,widget->allocation.y,
       t@@ -1744,6 +1851,7 @@ void gtk_clist_realize(GtkWidget *widget) {
        
           gtk_container_realize(widget);
           Parent=gtk_get_parent_hwnd(widget);
       +   GTK_WIDGET_SET_FLAGS(widget,GTK_CAN_FOCUS);
           rcParent.left = rcParent.top = 0;
           rcParent.right = rcParent.bottom = 800;
           header=CreateWindowEx(0,WC_HEADER,NULL,
       t@@ -2962,8 +3070,9 @@ void gtk_notebook_realize(GtkWidget *widget) {
           TC_ITEM tie;
        
           Parent=gtk_get_parent_hwnd(widget);
       +   GTK_WIDGET_SET_FLAGS(widget,GTK_CAN_FOCUS);
           widget->hWnd = CreateWindow(WC_TABCONTROL,"",
       -                               WS_CHILD,0,0,0,0,
       +                               WS_CHILD|WS_TABSTOP,0,0,0,0,
                                       Parent,NULL,hInst,NULL);
           if (widget->hWnd==NULL) g_print("Error creating window!\n");
           gtk_set_default_font(widget->hWnd);
       t@@ -3174,7 +3283,8 @@ void gtk_spin_button_realize(GtkWidget *widget) {
           gtk_entry_realize(widget);
        
           Parent=gtk_get_parent_hwnd(widget->parent);
       -   spin->updown=CreateUpDownControl(WS_CHILD|WS_BORDER|
       +   GTK_WIDGET_SET_FLAGS(widget,GTK_CAN_FOCUS);
       +   spin->updown=CreateUpDownControl(WS_CHILD|WS_BORDER|WS_TABSTOP|
                                UDS_SETBUDDYINT|UDS_NOTHOUSANDS|UDS_ARROWKEYS,
                                0,0,0,0,Parent,0,hInst,widget->hWnd,20,10,15);
           gtk_set_default_font(spin->updown);
       t@@ -3270,6 +3380,9 @@ void gtk_widget_grab_default(GtkWidget *widget) {
        }
        
        void gtk_widget_grab_focus(GtkWidget *widget) {
       +   if (widget->hWnd && GTK_WIDGET_CAN_FOCUS(widget)) {
       +      SetFocus(widget->hWnd);
       +   }
        }
        
        void gtk_window_set_modal(GtkWindow *window,gboolean modal) {
       t@@ -3524,6 +3637,7 @@ void gtk_option_menu_realize(GtkWidget *widget) {
           GtkOptionMenu *option_menu=GTK_OPTION_MENU(widget);
        
           Parent=gtk_get_parent_hwnd(widget);
       +   GTK_WIDGET_SET_FLAGS(widget,GTK_CAN_FOCUS);
           widget->hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,"COMBOBOX","",
                                         WS_CHILD|WS_TABSTOP|WS_VSCROLL|
                                         CBS_HASSTRINGS|CBS_DROPDOWNLIST,
       t@@ -3612,6 +3726,16 @@ void gtk_widget_set_usize(GtkWidget *widget,gint width,gint height) {
        }
        
        void gtk_clist_select_row(GtkCList *clist,gint row,gint column) {
       +   HWND hWnd;
       +   hWnd=GTK_WIDGET(clist)->hWnd;
       +   if (hWnd) {
       +      if (clist->mode==GTK_SELECTION_SINGLE) {
       +         SendMessage(hWnd,LB_SETCURSEL,(WPARAM)row,0);
       +      } else {
       +         SendMessage(hWnd,LB_SETSEL,(WPARAM)TRUE,(LPARAM)row);
       +      }
       +      gtk_clist_update_selection(GTK_WIDGET(clist));
       +   }
        }
        
        GtkVisibility gtk_clist_row_is_visible(GtkCList *clist,gint row) {
 (DIR) diff --git a/src/gtk.h b/src/gtk.h
       t@@ -48,6 +48,8 @@ typedef enum {
           GTK_REALIZED    = 1 << 6,
           GTK_VISIBLE     = 1 << 8,
           GTK_SENSITIVE   = 1 << 10,
       +   GTK_CAN_FOCUS   = 1 << 11,
       +   GTK_HAS_FOCUS   = 1 << 12,
           GTK_CAN_DEFAULT = 1 << 13
        } GtkWidgetFlags;
        
       t@@ -366,6 +368,7 @@ struct _GtkWindow {
           gint default_width,default_height;
           GtkMenuBar *menu_bar;
           GtkAccelGroup *accel_group;
       +   GtkWidget *focus;
           HACCEL hAccel;
           guint modal : 1;
        };
       t@@ -430,6 +433,8 @@ struct _GtkTableRowCol {
        #define GTK_WIDGET_REALIZED(wid) ((GTK_WIDGET_FLAGS(wid)&GTK_REALIZED) != 0)
        #define GTK_WIDGET_VISIBLE(wid) ((GTK_WIDGET_FLAGS(wid)&GTK_VISIBLE) != 0)
        #define GTK_WIDGET_SENSITIVE(wid) ((GTK_WIDGET_FLAGS(wid)&GTK_SENSITIVE) != 0)
       +#define GTK_WIDGET_CAN_FOCUS(wid) ((GTK_WIDGET_FLAGS(wid)&GTK_CAN_FOCUS) != 0)
       +#define GTK_WIDGET_HAS_FOCUS(wid) ((GTK_WIDGET_FLAGS(wid)&GTK_HAS_FOCUS) != 0)
        #define GTK_WIDGET_SET_FLAGS(wid,flag) (GTK_WIDGET_FLAGS(wid) |= (flag))
        #define GTK_WIDGET_UNSET_FLAGS(wid,flag) (GTK_WIDGET_FLAGS(wid) &= ~(flag))