View Issue Details

IDProjectCategoryView StatusLast Update
0037269LazarusWidgetsetpublic2020-07-22 11:04
ReporterCudaText man Assigned ToJuha Manninen  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version2.1 (SVN) 
Summary0037269: gtk3 - all messageboxes are screwed up
Descriptionhttps://github.com/Alexey-T/Lazarus_test_messageboxes
Run this demo on gtk2, check how app shows good result of pressed buttons for all msgbox kinds.
Run on gtk3.
check that all msgbox kinds geet WRONG result. e.g. first 3 kinds for Yes/No/Cancel return 'yes' for pressed cancel; 'cancel' for pressed yes.
Last kind - AskUser - bad too!
TagsNo tags attached.
Fixed in Revisionr63594, r63604
LazTarget-
WidgetsetGTK 3
Attached Files

Activities

Anton Kavalenka

2020-07-17 18:33

reporter   ~0124128

Last edited: 2020-07-18 07:47

View 2 revisions

Significantly simplified an reworked to TGtk3DialogFactory. At least it works in some degree.
mapping of GTK response code to modal results mrXXXX have to be examined carefully.
gtk3lclintf.diff (19,236 bytes)   
Index: lcl/interfaces/gtk3/gtk3lclintf.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3lclintf.inc	(revision 63591)
+++ lcl/interfaces/gtk3/gtk3lclintf.inc	(working copy)
@@ -1076,123 +1076,172 @@
   Result := False;
 end;
 
-function TGtk3WidgetSet.AskUser(const DialogCaption, DialogMessage: string; DialogType:
-   LongInt; Buttons: TDialogButtons; HelpCtx: Longint): LongInt;
 
-const
-  ButtonResults : array[mrNone..mrYesToAll] of Longint = (
-    -1, idButtonOK, idButtonCancel, idButtonAbort, idButtonRetry,
-    idButtonIgnore, idButtonYes,idButtonNo, idButtonAll, idButtonNoToAll,
-    idButtonYesToAll);
+type
+  TBtnListfunction=function(ndx:integer):longint of object;
+  TGtk3DialogFactory = class
+    btn_def: PGtkButton;
+    DefaultNdx: Integer;
+    fButtons: TDialogButtons;
+    pButtons: PLongint;
+    fCaption: string;
+    fDialogType:longint;
+    Dialog: PGtkMessageDialog;
+    DialogResult: Integer;
+    constructor CreateAsk(const DialogCaption, DialogMessage: string;
+       DialogType: LongInt; Buttons: TDialogButtons; HelpCtx: Longint);
+    constructor CreatePrompt(const DialogCaption, DialogMessage: string;
+       DialogType: LongInt; Buttons: PLongInt;
+       ButtonCount: LongInt; DefaultIndex: LongInt; EscapeResult: LongInt);
+    class function tr(UseWidgetStr: boolean; const TranslatedStr, WidgetStr: String): string;
+    destructor Destroy;override;
+    procedure run;
+    function btn_coll_info(ndx:integer):longint;
+    function btn_ptr_info(ndx:integer):longint;
+    procedure update_widget_list(const func:TBtnListFunction);
+    procedure CreateButton(const ALabel : String; const AResponse: Integer;
+      const AImageHint: Integer = -1);
+    class function ResponseID(const AnID: Integer): Integer;
+    class function gtk_resp_to_lcl(const gtk_resp:integer):integer;
+    class function MessageType(ADialogType:longint):TGtkMessageType;
+  end;
 
+class function TGtk3DialogFactory.ResponseID(const AnID: Integer): Integer;
+begin
+  case AnID of
+    idButtonOK       : Result := GTK_RESPONSE_OK;
+    idButtonCancel   : Result := GTK_RESPONSE_CANCEL;
+    idButtonHelp     : Result := GTK_RESPONSE_HELP;
+    idButtonYes      : Result := GTK_RESPONSE_YES;
+    idButtonNo       : Result := GTK_RESPONSE_NO;
+    idButtonClose    : Result := GTK_RESPONSE_CLOSE;
+    idButtonAbort    : Result := GTK_RESPONSE_REJECT;
+    idButtonRetry    : Result := GTK_RESPONSE_LCL_RETRY;
+    idButtonIgnore   : Result := GTK_RESPONSE_LCL_IGNORE;
+    idButtonAll      : Result := GTK_RESPONSE_LCL_ALL;
+    idButtonNoToAll  : Result := GTK_RESPONSE_LCL_NOTOALL;
+    idButtonYesToAll : Result := GTK_RESPONSE_LCL_YESTOALL;
+  else
+    Result:=AnID;
+  end;
+end;
+
+
+class function TGtk3DialogFactory.gtk_resp_to_lcl(const gtk_resp:integer):integer;
+begin
+  case gtk_resp of
+  -5{GTK_RESPONSE_OK}: Result:=  mrOK;
+  -6{GTK_RESPONSE_CANCEL}:  Result := mrCancel;
+  -7{GTK_RESPONSE_CLOSE}: Result:=mrClose;
+  -8{GTK_RESPONSE_YES}: Result:=mrYes;
+  -9{GTK_RESPONSE_NO}: Result:=mrNo;
+  -10{GTK_RESPONSE_APPLY}: Result:=mrAll;
+//  -11{GTK_RESPONSE_HELP}: Result:=mrhelp;
+
+  -1{GTK_RESPONSE_NONE}: Result:=mrNone;
+  -2{GTK_RESPONSE_REJECT}: Result:=mrAbort;
+  -3{GTK_RESPONSE_ACCEPT}: Result:=mrAll;
+  else
+    Result:=gtk_resp;
+  end;
+end;
+
+procedure TGtk3DialogFactory.CreateButton(
+    const ALabel : String;
+    const AResponse: Integer;
+    const AImageHint: Integer = -1);
 var
-  Btn,btn_def: PGtkButton;
-  BtnId: Longint;
-  Dialog: PGtkMessageDialog;
-  ADialogResult: Integer;
-  GtkDialogType: TGtkMessageType;
-  Btns: TGtkButtonsType;
-  BtnIdx: Integer;
-  DefaultNdx: Integer;
-  X: Integer;
-  MainList,ChildList: PGList;
-  Title: String;
-  //ActiveWindow: HWND;
-  BtnResult: LongInt;
-  n: Integer;
-  dbtn:TDialogButton;
+  NewButton: PGtkWidget;
+  //BitmapHandle, MaskHandle: HBitmap;
+  // GDIObject: PGDIObject;
+  //Pixbuf: PGdkPixbuf;
+  // Mask: PGdkBitmap;
+  //Img: PGtkWidget;
+begin
 
-  procedure CreateButton(const ALabel : String; const AResponse: Integer;
-      const AImageHint: Integer = -1);
-  var
-    NewButton: PGtkWidget;
-    //BitmapHandle, MaskHandle: HBitmap;
-    // GDIObject: PGDIObject;
-    //Pixbuf: PGdkPixbuf;
-    // Mask: PGdkBitmap;
-    //Img: PGtkWidget;
+  NewButton := gtk_dialog_add_button(Dialog,
+    PgChar({Ampersands2Underscore}(ALabel)), AResponse);
+  gtk_button_set_use_underline(PGtkButton(NewButton), True);
+  g_object_set_data(PGObject(NewButton), 'modal_result',
+        {%H-}Pointer(PtrInt(AResponse)));
+  (*
+  if AImageHint >= 0 then
   begin
-
-    NewButton := gtk_dialog_add_button(Dialog,
-      PgChar({Ampersands2Underscore}(ALabel)), AResponse);
-    gtk_button_set_use_underline(PGtkButton(NewButton), True);
-    g_object_set_data(PGObject(NewButton), 'modal_result',
-          {%H-}Pointer(PtrInt(AResponse)));
-    (*
-    if AImageHint >= 0 then
+    if ThemeServices.GetStockImage(AImageHint, BitmapHandle, MaskHandle) then
     begin
-      if ThemeServices.GetStockImage(AImageHint, BitmapHandle, MaskHandle) then
-      begin
-        GDIObject := {%H-}PGDIObject(BitmapHandle);
-        Mask := nil;
-        Pixbuf := nil;
-        if GDIObject^.GDIBitmapType = gbPixbuf then
-          Pixbuf := GDIObject^.GDIPixbufObject
-        else
-          Mask := CreateGdkMaskBitmap(BitmapHandle, MaskHandle);
+      GDIObject := {%H-}PGDIObject(BitmapHandle);
+      Mask := nil;
+      Pixbuf := nil;
+      if GDIObject^.GDIBitmapType = gbPixbuf then
+        Pixbuf := GDIObject^.GDIPixbufObject
+      else
+        Mask := CreateGdkMaskBitmap(BitmapHandle, MaskHandle);
 
-        Img := gtk_image_new;
+      Img := gtk_image_new;
 
-        if Pixbuf <> nil then
-          gtk_image_set_from_pixbuf(PGtkImage(Img), Pixbuf)
-        else
-          gtk_image_set_from_pixmap(PGtkImage(Img), GDIObject^.GDIPixmapObject.Image, Mask);
-        gtk_button_set_image(PGtkButton(NewButton), Img);
-        if Mask <> nil then
-          g_object_unref(Mask);
-        DeleteObject(BitmapHandle);
-        DeleteObject(MaskHandle);
-      end;
+      if Pixbuf <> nil then
+        gtk_image_set_from_pixbuf(PGtkImage(Img), Pixbuf)
+      else
+        gtk_image_set_from_pixmap(PGtkImage(Img), GDIObject^.GDIPixmapObject.Image, Mask);
+      gtk_button_set_image(PGtkButton(NewButton), Img);
+      if Mask <> nil then
+        g_object_unref(Mask);
+      DeleteObject(BitmapHandle);
+      DeleteObject(MaskHandle);
     end;
-    *)
   end;
+  *)
+end;
 
-  function ResponseID(const AnID: Integer): Integer;
-  begin
-    case AnID of
-      idButtonOK       : Result := GTK_RESPONSE_OK;
-      idButtonCancel   : Result := GTK_RESPONSE_CANCEL;
-      idButtonHelp     : Result := GTK_RESPONSE_HELP;
-      idButtonYes      : Result := GTK_RESPONSE_YES;
-      idButtonNo       : Result := GTK_RESPONSE_NO;
-      idButtonClose    : Result := GTK_RESPONSE_CLOSE;
-      idButtonAbort    : Result := GTK_RESPONSE_REJECT;
-      idButtonRetry    : Result := GTK_RESPONSE_LCL_RETRY;
-      idButtonIgnore   : Result := GTK_RESPONSE_LCL_IGNORE;
-      idButtonAll      : Result := GTK_RESPONSE_LCL_ALL;
-      idButtonNoToAll  : Result := GTK_RESPONSE_LCL_NOTOALL;
-      idButtonYesToAll : Result := GTK_RESPONSE_LCL_YESTOALL;
-    else
-      Result:=AnID;
-    end;
-  end;
+class function TGtk3DialogFactory.MessageType(ADialogType:longint):TGtkMessageType;
 begin
-  Result := mrNone;
-  ReleaseCapture;
-  ADialogResult := mrNone;
-  case DialogType of
-    idDialogWarning: GtkDialogType := GTK_MESSAGE_WARNING;
-    idDialogError: GtkDialogType := GTK_MESSAGE_ERROR;
-    idDialogInfo : GtkDialogType := GTK_MESSAGE_INFO;
-    idDialogConfirm : GtkDialogType := GTK_MESSAGE_QUESTION;
+  case ADialogType of
+    idDialogWarning: Result := GTK_MESSAGE_WARNING;
+    idDialogError: Result := GTK_MESSAGE_ERROR;
+    idDialogInfo : Result := GTK_MESSAGE_INFO;
+    idDialogConfirm : Result := GTK_MESSAGE_QUESTION;
   else
-    GtkDialogType := GTK_MESSAGE_INFO;
+    Result := GTK_MESSAGE_INFO;
   end;
+end;
 
+
+const
+  ButtonResults : array[mrNone..mrYesToAll] of Longint = (
+    -1, idButtonOK, idButtonCancel, idButtonAbort, idButtonRetry,
+    idButtonIgnore, idButtonYes,idButtonNo, idButtonAll, idButtonNoToAll,
+    idButtonYesToAll);
+
+constructor TGtk3DialogFactory.CreateAsk(const DialogCaption,
+       DialogMessage: string; DialogType: LongInt;
+       Buttons: TDialogButtons; HelpCtx: Longint);
+var
+  GtkDialogType: TGtkMessageType;
+  Btns: TGtkButtonsType;
+  i, BtnIdx, BtnID: Integer;
+  dbtn:TDialogButton;
+  Title: String;
+  BtnResult: LongInt;
+begin
+  DialogResult := mrNone;
+  fDialogType := DialogType;
+  GtkDialogType := MessageType(fDialogType); // map LCLINTF -> GTK
+  fButtons:=Buttons;
+  fCaption:=DialogCaption;
+
   Btns := GTK_BUTTONS_NONE;
   DefaultNdx := 0;
-  for X := 0 to Buttons.Count - 1 do
+  for i := 0 to Buttons.Count - 1 do
   begin
-    if Buttons[X].Default then
-      DefaultNdx := X;
+    if Buttons[i].Default then
+      DefaultNdx := i;
 
-    if (ADialogResult = mrNone) and
-      (Buttons[X].ModalResult in [mrCancel, mrAbort, mrIgnore,
-        mrNo, mrNoToAll]) then
-      ADialogResult := Buttons[X].ModalResult;
+    if (DialogResult = mrNone) and
+      (Buttons[i].ModalResult in [mrCancel, mrAbort, mrIgnore, mrNo, mrNoToAll])
+    then
+      DialogResult := Buttons[i].ModalResult;
   end;
 
-
   Dialog := gtk_message_dialog_new(nil, GTK_DIALOG_MODAL, GtkDialogType, Btns, nil , []);
 
   gtk_message_dialog_set_markup(PGtkMessageDialog(Dialog), PGChar(DialogMessage));
@@ -1199,11 +1248,11 @@
 
   g_signal_connect_data(Dialog, 'delete-event',
     TGCallback(@PromptUserBoxClosed),
-    @ADialogResult, nil, 0);
+    @DialogResult, nil, 0);
 
   if Btns = GTK_BUTTONS_NONE then
   begin
-    // gtk2 have reverted buttons eg. No, Yes
+    // gtk3 have reverted buttons eg. No, Yes
     for BtnIdx := Buttons.Count - 1 downto 0 do
     begin
       dbtn:=Buttons[BtnIdx];
@@ -1229,6 +1278,28 @@
 
     end;
   end;
+
+  update_widget_list(@btn_coll_info);
+
+end;
+
+
+function TGtk3DialogFactory.btn_coll_info(ndx:integer):longint;
+begin
+  Result:=fButtons[ndx].ModalResult; // get modal result for button
+end;
+
+function TGtk3DialogFactory.btn_ptr_info(ndx:integer):longint;
+begin
+  Result:=pButtons[ndx];
+end;
+
+procedure TGtk3DialogFactory.update_widget_list(const func:TBtnListFunction);
+var
+  btn:PgtkButton;
+  BtnIdx,BtnID,BtnRes:integer;
+  MainList,ChildList: PGList;
+begin
   MainList := gtk_container_get_children(PGtkContainer(Dialog^.get_action_area));
   ChildList:=g_list_last(MainList);
   BtnIdx:=0;
@@ -1240,20 +1311,19 @@
       if g_type_check_instance_is_a(ChildList^.Data, gtk_button_get_type) then
       begin
         Btn := PGtkButton(ChildList^.Data);
-       // writeln('btn[',BtnIdx,'] ',Btn^.get_label);
-        BtnID := -1;
-        dbtn:=Buttons[BtnIdx];
-        BtnResult:=dbtn.ModalResult;
-        if (BtnResult>=Low(ButtonResults)) and (BtnResult<=High(ButtonResults)) then
-          BtnID := ButtonResults[dbtn.ModalResult]
+
+        BtnRes:=func(BtnIdx); // process button
+
+        if (BtnRes>=Low(ButtonResults)) and (BtnRes<=High(ButtonResults)) then
+          BtnID := ButtonResults[BtnRes]
         else
-          BtnID := dbtn.ModalResult;
+          BtnID := BtnRes;
 
         if BtnID = idButtonCancel then
-          g_object_set_data(PGObject(Dialog), 'modal_result', Pointer(idButtonCancel));
+           g_object_set_data(PGObject(Dialog), 'modal_result', Pointer(idButtonCancel));
 
         g_signal_connect_data(Btn, 'clicked',
-          TGCallback(@PromptUserButtonClicked), @ADialogResult, nil, 0);
+          TGCallback(@PromptUserButtonClicked), @DialogResult, nil, 0);
 
         if DefaultNdx = BtnIdx then
         begin
@@ -1275,24 +1345,58 @@
   if MainList <> nil then
     g_list_free(MainList);
 
-  if DialogCaption <> '' then
-    gtk_window_set_title(PGtkWindow(Dialog), PGChar(DialogCaption))
+end;
+
+procedure TGtk3DialogFactory.run;
+var
+  Title:string;
+begin
+  if not Assigned(Dialog) then exit;
+
+  if fCaption <> '' then
+    Title:=fCaption
   else
   begin
     Title := '';
-    case DialogType of
+    case fDialogType of
       idDialogWarning: Title := rsMtWarning;
       idDialogError: Title := rsMtError;
       idDialogInfo : Title := rsMtInformation;
       idDialogConfirm : Title := rsMtConfirmation;
     end;
-    gtk_window_set_title(PGtkWindow(Dialog), PGChar(Title));
   end;
 
+  gtk_window_set_title(PGtkWindow(Dialog), PGChar(Title));
   gtk_dialog_run(Dialog);
+  Self.DialogResult:=Self.gtk_resp_to_lcl(Self.DialogResult);
+end;
+
+class function TGtk3DialogFactory.tr(UseWidgetStr: boolean; const TranslatedStr, WidgetStr: String): string;
+begin
+  if UseWidgetStr then
+    Result:=WidgetStr
+  else
+    Result:=TranslatedStr;
+end;
+
+destructor TGtk3DialogFactory.Destroy;
+begin
+  if Assigned(Dialog) then
   gtk_widget_destroy(Dialog);
+end;
 
-  Result := ADialogResult;
+function TGtk3WidgetSet.AskUser(const DialogCaption, DialogMessage: string; DialogType:
+   LongInt; Buttons: TDialogButtons; HelpCtx: Longint): LongInt;
+var
+  fact:TGtk3DialogFactory;
+begin
+  fact:=TGtk3DialogFactory.CreateAsk(DialogCaption,DialogMessage,DialogType,Buttons,HelpCtx);
+  try
+    fact.run;
+    Result := fact.DialogResult;
+  finally
+    fact.Free;
+  end;
 end;
 
 function TGtk3WidgetSet.PromptUser(const DialogCaption: string;
@@ -1299,65 +1403,33 @@
   const DialogMessage: string; DialogType: LongInt; Buttons: PLongInt;
   ButtonCount: LongInt; DefaultIndex: LongInt; EscapeResult: LongInt): LongInt;
 var
-  Btn: PGtkButton;
-  Dialog: PGtkMessageDialog;
-  ADialogResult: Integer;
+  fact:TGtk3DialogFactory;
+begin
+  fact:=TGtk3DialogFactory.CreatePrompt(DialogCaption,DialogMessage,
+     DialogType,Buttons,ButtonCount,DefaultIndex,EscapeResult);
+  try
+    fact.run;
+    Result:=fact.DialogResult;
+  finally
+    fact.Free;
+  end;
+
+end;
+
+constructor TGtk3DialogFactory.CreatePrompt(const DialogCaption: string;
+     const DialogMessage: string; DialogType: LongInt; Buttons: PLongInt;
+    ButtonCount: LongInt; DefaultIndex: LongInt; EscapeResult: LongInt);
+var
+  x,i:integer;
   GtkDialogType: TGtkMessageType;
   Btns: TGtkButtonsType;
-  BtnIdx: Integer;
   DefaultID: Integer;
-  X: Integer;
-  MainList,ChildList: PGList;
-  Title: String;
-  n: Integer;
-
-  procedure CreateButton(const ALabel : String; const AResponse: Integer);
-  var
-    NewButton: PGtkButton;
-  begin
-    NewButton := PGtkButton(gtk_dialog_add_button(Dialog,
-      PgChar(ALabel), AResponse));
-    gtk_button_set_use_underline(NewButton, True);
-  end;
-
-  function tr(UseWidgetStr: boolean; const TranslatedStr, WidgetStr: String): string;
-  begin
-    if UseWidgetStr then
-      Result:=WidgetStr
-    else
-      Result:=TranslatedStr;
-  end;
-
-  function ResponseID(const AnID: Integer): Integer;
-  begin
-    case AnID of
-      idButtonOK       : Result := GTK_RESPONSE_OK;
-      idButtonCancel   : Result := GTK_RESPONSE_CANCEL;
-      idButtonHelp     : Result := GTK_RESPONSE_HELP;
-      idButtonYes      : Result := GTK_RESPONSE_YES;
-      idButtonNo       : Result := GTK_RESPONSE_NO;
-      idButtonClose    : Result := GTK_RESPONSE_CLOSE;
-      idButtonAbort    : Result := GTK_RESPONSE_REJECT;
-      idButtonRetry    : Result := GTK_RESPONSE_LCL_RETRY;
-      idButtonIgnore   : Result := GTK_RESPONSE_LCL_IGNORE;
-      idButtonAll      : Result := GTK_RESPONSE_LCL_ALL;
-      idButtonNoToAll  : Result := GTK_RESPONSE_LCL_NOTOALL;
-      idButtonYesToAll : Result := GTK_RESPONSE_LCL_YESTOALL;
-    end;
-  end;
-
 begin
-  Result := -1;
-  ReleaseCapture;
-  ADialogResult := EscapeResult;
-  case DialogType of
-    idDialogWarning: GtkDialogType := GTK_MESSAGE_WARNING;
-    idDialogError: GtkDialogType := GTK_MESSAGE_ERROR;
-    idDialogInfo : GtkDialogType := GTK_MESSAGE_INFO;
-    idDialogConfirm : GtkDialogType := GTK_MESSAGE_QUESTION;
-  else
-    GtkDialogType := GTK_MESSAGE_INFO;
-  end;
+  DialogResult := EscapeResult;
+  fDialogType := DialogType;
+  GtkDialogType := MessageType(fDialogType); // map LCLINTF -> GTK
+  pButtons:=Buttons;
+  fCaption:=DialogCaption;
 
   Btns := GTK_BUTTONS_NONE;
   DefaultId := 0;
@@ -1373,13 +1445,13 @@
 
   g_signal_connect_data(GPointer(Dialog), 'delete-event',
     TGCallback(@PromptUserBoxClosed),
-    @ADialogResult, nil, 0);
+    @DialogResult, nil, 0);
 
   if Btns = GTK_BUTTONS_NONE then
   begin
-    for BtnIdx := ButtonCount-1 downto 0 do
+    for i := ButtonCount-1 downto 0 do
     begin
-      case Buttons[BtnIdx] of
+      case Buttons[i] of
         idButtonOK       : CreateButton(tr(rsmbOK='&OK',rsmbOK, 'gtk-ok'), GTK_RESPONSE_OK);
         idButtonCancel   : CreateButton(tr(rsmbCancel='Cancel',rsmbCancel,'gtk-cancel'), GTK_RESPONSE_CANCEL);
         idButtonHelp     : CreateButton(tr(rsmbHelp='&Help',rsmbHelp,'gtk-help'), GTK_RESPONSE_HELP);
@@ -1395,67 +1467,7 @@
       end;
     end;
   end;
-
-  MainList := gtk_container_get_children(PGtkContainer(Dialog^.get_action_area));
-  ChildList := MainList;
-  BtnIdx := 0;
-  n := 0;
-  while ChildList <> nil do
-  begin
-    if (ChildList^.Data <> nil) then
-    begin
-      if g_type_check_instance_is_a(ChildList^.Data, gtk_button_get_type) then
-      begin
-        Btn := PGtkButton(ChildList^.Data);
-
-        if Buttons[BtnIdx] = idButtonCancel then
-          g_object_set_data(PGObject(Dialog), 'modal_result', Pointer(idButtonCancel));
-
-        X := Buttons[BtnIdx];
-        g_object_set_data(PGObject(Btn), 'modal_result',
-          {%H-}Pointer(PtrInt(X)));
-
-        g_signal_connect_data(gPointer(Btn), 'clicked',
-          TGCallback(@PromptUserButtonClicked), @ADialogResult, nil, 0);
-
-        if DefaultID = Buttons[BtnIdx] then
-        begin
-          gtk_dialog_set_default_response(Dialog, ResponseID(Buttons[BtnIdx]));
-          X := Buttons[BtnIdx];
-          g_object_set_data(PGObject(Dialog), 'modal_result',
-            {%H-}Pointer(PtrInt(X)));
-        end;
-
-        inc(BtnIdx);
-      end;
-    end;
-    inc(n);
-    ChildList := g_list_nth(ChildList, n);
-    // ChildList := g_list_next(ChildList);
-  end;
-  if MainList <> nil then
-    g_list_free(MainList);
-
-  if DialogCaption <> '' then
-    gtk_window_set_title(PGtkWindow(Dialog), PGChar(DialogCaption))
-  else
-  begin
-    Title := '';
-    case DialogType of
-      idDialogWarning: Title := rsMtWarning;
-      idDialogError: Title := rsMtError;
-      idDialogInfo : Title := rsMtInformation;
-      idDialogConfirm : Title := rsMtConfirmation;
-    end;
-    gtk_window_set_title(PGtkWindow(Dialog), PGChar(Title));
-  end;
-
-  // do not allow jump to GtkLabel from button via Tab ?
-  // if Gtk3IsBox(Dialog^.get_message_area) then
-  //  PGtkBox(Dialog^.get_message_area)^.set_focus_chain(nil);
-  gtk_dialog_run(Dialog);
-  gtk_widget_destroy(Dialog);
-  Result := ADialogResult;
+  update_widget_list(@btn_ptr_info);
 end;
 
 function TGtk3WidgetSet.SetComboMinDropDownSize(Handle: HWND; MinItemsWidth,
gtk3lclintf.diff (19,236 bytes)   

Juha Manninen

2020-07-17 19:43

developer   ~0124130

Applied, thanks.

CudaText man

2020-07-17 23:46

reporter   ~0124134

It's better!
gtk3 - still bad with

- application.messagebox - with MB_YESNOCANCEL (most results wrong)
- messagedlg - with MB_YESNOCANCEL
- propmtuser - with MB_YESNOCANCEL
- askuser - bad result for button "ignore"

Anton Kavalenka

2020-07-19 09:32

reporter   ~0124167

Factored out all message boxes from gtk3winapi.inc and gtk3lclintf.inc into gtk3boxes.pas
All messageboxes now created through the factory, so look and feel is consistent.
Kept old code of manual-crafted messagebox in .CreateMsgBox1
gtk3.diff (37,871 bytes)   
Index: lcl/interfaces/gtk3/gtk3boxes.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3boxes.pas	(nonexistent)
+++ lcl/interfaces/gtk3/gtk3boxes.pas	(working copy)
@@ -0,0 +1,565 @@
+unit gtk3boxes;
+
+interface
+
+uses
+  lcltype,
+  interfacebase,
+  lazgtk3;
+
+type
+  TBtnListfunction=function(ndx:integer):longint of object;
+
+  { TGtk3DialogFactory }
+
+  TGtk3DialogFactory = class
+    btn_def: PGtkButton;
+    DefaultNdx: Integer;
+    fButtons: TDialogButtons;
+    pButtons: PLongint;
+    fCaption: string;
+    fDialogType:longint;
+    Dialog: PGtkDialog;
+    DialogResult: Integer;
+    constructor CreateAsk(const DialogCaption, DialogMessage: string;
+       DialogType: LongInt; Buttons: TDialogButtons; HelpCtx: Longint);
+    constructor CreatePrompt(const DialogCaption, DialogMessage: string;
+       DialogType: LongInt; Buttons: PLongInt;
+       ButtonCount: LongInt; DefaultIndex: LongInt; EscapeResult: LongInt);
+    constructor CreateMsgBox(hWnd: HWND; lpText, lpCaption: PChar;
+       uType: Cardinal);
+    constructor CreateMsgBox1(hWnd: HWND; lpText, lpCaption: PChar;
+       uType: Cardinal);
+    class function tr(UseWidgetStr: boolean; const TranslatedStr, WidgetStr: String): string;
+    destructor Destroy;override;
+    procedure run;
+    function btn_coll_info(ndx:integer):longint;
+    function btn_ptr_info(ndx:integer):longint;
+    procedure update_widget_list(const func:TBtnListFunction);
+    procedure CreateButton(const ALabel : String; const AResponse: Integer;
+      const AImageHint: Integer = -1);
+    class function ResponseID(const AnID: Integer): Integer;
+    class function gtk_resp_to_lcl(const gtk_resp:integer):integer;
+    class function MessageType(ADialogType:longint):TGtkMessageType;
+  end;
+
+
+implementation
+uses lclstrconsts,lclproc,uitypes,lazglib2,lazgobject2,lazgdk3,gtk3objects;
+
+// fake GTK button responses
+const
+  GTK_RESPONSE_LCL_ALL = -10;
+  GTK_RESPONSE_LCL_YESTOALL = -3; // GTK_RESPONSE_ACCEPT;
+  GTK_RESPONSE_LCL_RETRY = -12;
+  GTK_RESPONSE_LCL_IGNORE = -13;
+  GTK_RESPONSE_LCL_NOTOALL = -14;
+
+
+{ callbacks }
+function BoxClosed(Widget : PGtkWidget; {%H-}Event : PGdkEvent;
+  data: gPointer) : GBoolean; cdecl;
+var
+  ModalResult : PtrUInt;
+begin
+  { We were requested by window manager to close so return EscapeResult}
+  if PInteger(data)^ = 0 then
+  begin
+    ModalResult:= {%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
+    { Don't allow to close if we don't have a default return value }
+    Result:= (ModalResult = 0);
+    if not Result then PInteger(data)^:= ModalResult
+    else DebugLn('Do not close !!!');
+  end else Result:= false;
+end;
+
+function ButtonClicked(Widget : PGtkWidget; data: gPointer) : GBoolean; cdecl;
+begin
+  PInteger(data)^ := {%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
+  Result := False;
+end;
+
+
+
+class function TGtk3DialogFactory.ResponseID(const AnID: Integer): Integer;
+begin
+  case AnID of
+    idButtonOK       : Result := GTK_RESPONSE_OK;
+    idButtonCancel   : Result := GTK_RESPONSE_CANCEL;
+    idButtonHelp     : Result := GTK_RESPONSE_HELP;
+    idButtonYes      : Result := GTK_RESPONSE_YES;
+    idButtonNo       : Result := GTK_RESPONSE_NO;
+    idButtonClose    : Result := GTK_RESPONSE_CLOSE;
+    idButtonAbort    : Result := GTK_RESPONSE_REJECT;
+    idButtonRetry    : Result := GTK_RESPONSE_LCL_RETRY;
+    idButtonIgnore   : Result := GTK_RESPONSE_LCL_IGNORE;
+    idButtonAll      : Result := GTK_RESPONSE_LCL_ALL;
+    idButtonNoToAll  : Result := GTK_RESPONSE_LCL_NOTOALL;
+    idButtonYesToAll : Result := GTK_RESPONSE_LCL_YESTOALL;
+  else
+    Result:=AnID;
+  end;
+end;
+
+
+class function TGtk3DialogFactory.gtk_resp_to_lcl(const gtk_resp:integer):integer;
+begin
+  case gtk_resp of
+  -5{GTK_RESPONSE_OK}: Result:=  ID_OK;
+  -6{GTK_RESPONSE_CANCEL}:  Result := id_Cancel;
+  -7{GTK_RESPONSE_CLOSE}: Result:=id_Close;
+  -8{GTK_RESPONSE_YES}: Result:=id_Yes;
+  -9{GTK_RESPONSE_NO}: Result:=id_No;
+
+  -1{GTK_RESPONSE_NONE}: Result:=0;
+  -2{GTK_RESPONSE_REJECT}: Result:=id_abort;
+  -3{GTK_RESPONSE_ACCEPT}: Result:=id_Yes;
+
+  GTK_RESPONSE_LCL_RETRY: Result:=id_Retry;
+  GTK_RESPONSE_LCL_IGNORE:  Result:=id_Ignore;
+  GTK_RESPONSE_LCL_ALL:  Result:=idButtonAll;
+  GTK_RESPONSE_LCL_NOTOALL: Result:=idButtonNoToAll;
+  //GTK_RESPONSE_LCL_YESTOALL: Result:= idButtonYesToAll;
+  else
+    Result:=gtk_resp;
+  end;
+end;
+
+procedure TGtk3DialogFactory.CreateButton(
+    const ALabel : String;
+    const AResponse: Integer;
+    const AImageHint: Integer = -1);
+var
+  NewButton: PGtkWidget;
+  //BitmapHandle, MaskHandle: HBitmap;
+  // GDIObject: PGDIObject;
+  //Pixbuf: PGdkPixbuf;
+  // Mask: PGdkBitmap;
+  //Img: PGtkWidget;
+begin
+
+  NewButton := gtk_dialog_add_button(Dialog,
+    PgChar(ReplaceAmpersandsWithUnderscores(ALabel)), AResponse);
+  gtk_button_set_use_underline(PGtkButton(NewButton), True);
+  g_object_set_data(PGObject(NewButton), 'modal_result',
+        {%H-}Pointer(PtrInt(AResponse)));
+  (*
+  if AImageHint >= 0 then
+  begin
+    if ThemeServices.GetStockImage(AImageHint, BitmapHandle, MaskHandle) then
+    begin
+      GDIObject := {%H-}PGDIObject(BitmapHandle);
+      Mask := nil;
+      Pixbuf := nil;
+      if GDIObject^.GDIBitmapType = gbPixbuf then
+        Pixbuf := GDIObject^.GDIPixbufObject
+      else
+        Mask := CreateGdkMaskBitmap(BitmapHandle, MaskHandle);
+
+      Img := gtk_image_new;
+
+      if Pixbuf <> nil then
+        gtk_image_set_from_pixbuf(PGtkImage(Img), Pixbuf)
+      else
+        gtk_image_set_from_pixmap(PGtkImage(Img), GDIObject^.GDIPixmapObject.Image, Mask);
+      gtk_button_set_image(PGtkButton(NewButton), Img);
+      if Mask <> nil then
+        g_object_unref(Mask);
+      DeleteObject(BitmapHandle);
+      DeleteObject(MaskHandle);
+    end;
+  end;
+  *)
+end;
+
+class function TGtk3DialogFactory.MessageType(ADialogType:longint):TGtkMessageType;
+begin
+  case ADialogType of
+    idDialogWarning: Result := GTK_MESSAGE_WARNING;
+    idDialogError: Result := GTK_MESSAGE_ERROR;
+    idDialogInfo : Result := GTK_MESSAGE_INFO;
+    idDialogConfirm : Result := GTK_MESSAGE_QUESTION;
+  else
+    Result := GTK_MESSAGE_INFO;
+  end;
+end;
+
+
+const
+  ButtonResults : array[mrNone..mrYesToAll] of Longint = (
+    -1, idButtonOK, idButtonCancel, idButtonAbort, idButtonRetry,
+    idButtonIgnore, idButtonYes,idButtonNo, idButtonAll, idButtonNoToAll,
+    idButtonYesToAll);
+
+constructor TGtk3DialogFactory.CreateAsk(const DialogCaption,
+       DialogMessage: string; DialogType: LongInt;
+       Buttons: TDialogButtons; HelpCtx: Longint);
+var
+  GtkDialogType: TGtkMessageType;
+  Btns: TGtkButtonsType;
+  i, BtnIdx, BtnID: Integer;
+  dbtn:TDialogButton;
+  Title: String;
+  BtnResult: LongInt;
+begin
+  DialogResult := mrNone;
+  fDialogType := DialogType;
+  GtkDialogType := MessageType(fDialogType); // map LCLINTF -> GTK
+  fButtons:=Buttons;
+  fCaption:=DialogCaption;
+
+  Btns := GTK_BUTTONS_NONE;
+  DefaultNdx := 0;
+  for i := 0 to Buttons.Count - 1 do
+  begin
+    if Buttons[i].Default then
+      DefaultNdx := i;
+
+    if (DialogResult = mrNone) and
+      (Buttons[i].ModalResult in [mrCancel, mrAbort, mrIgnore, mrNo, mrNoToAll])
+    then
+      DialogResult := Buttons[i].ModalResult;
+  end;
+
+  Dialog := gtk_message_dialog_new(nil, GTK_DIALOG_MODAL, GtkDialogType, Btns, nil , []);
+
+  gtk_message_dialog_set_markup(PGtkMessageDialog(Dialog), PGChar(DialogMessage));
+
+  g_signal_connect_data(Dialog, 'delete-event',
+    TGCallback(@BoxClosed),
+    @DialogResult, nil, 0);
+
+  if Btns = GTK_BUTTONS_NONE then
+  begin
+    // gtk3 have reverted buttons eg. No, Yes
+    for BtnIdx := Buttons.Count - 1 downto 0 do
+    begin
+      dbtn:=Buttons[BtnIdx];
+      if (dbtn.ModalResult >= Low(ButtonResults)) and (dbtn.ModalResult <= High(ButtonResults)) then
+      begin
+        BtnID := ButtonResults[dbtn.ModalResult];
+        case BtnID of
+          idButtonOK       : CreateButton(dbtn.Caption, GTK_RESPONSE_OK, BtnID);
+          idButtonCancel   : CreateButton(dbtn.Caption, GTK_RESPONSE_CANCEL, BtnID);
+          idButtonHelp     : CreateButton(dbtn.Caption, GTK_RESPONSE_HELP, BtnID);
+          idButtonYes      : CreateButton(dbtn.Caption, GTK_RESPONSE_YES, BtnID);
+          idButtonNo       : CreateButton(dbtn.Caption, GTK_RESPONSE_NO, BtnID);
+          idButtonClose    : CreateButton(dbtn.Caption, GTK_RESPONSE_CLOSE, BtnID);
+          idButtonAbort    : CreateButton(dbtn.Caption, GTK_RESPONSE_REJECT, BtnID);
+          idButtonRetry    : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_RETRY, BtnID);
+          idButtonIgnore   : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_IGNORE, BtnID);
+          idButtonAll      : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_ALL, BtnID);
+          idButtonNoToAll  : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_NOTOALL, BtnID);
+          idButtonYesToAll : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_YESTOALL, BtnID);
+        end;
+      end else
+         CreateButton(dbtn.Caption, dbtn.ModalResult, 0);
+
+    end;
+  end;
+
+  update_widget_list(@btn_coll_info);
+
+end;
+
+
+function TGtk3DialogFactory.btn_coll_info(ndx:integer):longint;
+begin
+  Result:=fButtons[ndx].ModalResult; // get modal result for button
+end;
+
+function TGtk3DialogFactory.btn_ptr_info(ndx:integer):longint;
+begin
+  Result:=pButtons[ndx];
+end;
+
+procedure TGtk3DialogFactory.update_widget_list(const func:TBtnListFunction);
+var
+  btn:PgtkButton;
+  BtnIdx,BtnID,BtnRes:integer;
+  MainList,ChildList: PGList;
+begin
+  MainList := gtk_container_get_children(PGtkContainer(Dialog^.get_action_area));
+  ChildList:=g_list_last(MainList);
+  BtnIdx:=0;
+  btn_def:=nil;
+  while Assigned(ChildList) do
+  begin
+    if (ChildList^.Data <> nil) then
+    begin
+      if g_type_check_instance_is_a(ChildList^.Data, gtk_button_get_type) then
+      begin
+        Btn := PGtkButton(ChildList^.Data);
+
+        BtnRes:=func(BtnIdx); // process button
+
+        if (BtnRes>=Low(ButtonResults)) and (BtnRes<=High(ButtonResults)) then
+          BtnID := ButtonResults[BtnRes]
+        else
+          BtnID := BtnRes;
+
+        if BtnID = idButtonCancel then
+           g_object_set_data(PGObject(Dialog), 'modal_result', Pointer(idButtonCancel));
+
+        g_signal_connect_data(Btn, 'clicked',
+          TGCallback(@ButtonClicked), @DialogResult, nil, 0);
+
+        if DefaultNdx = BtnIdx then
+        begin
+          gtk_dialog_set_default_response(Dialog, ResponseID(BtnID));
+          btn_def:=btn;
+          gtk_widget_grab_default(btn);
+          gtk_widget_grab_focus(btn);
+          gtk_widget_set_can_default(btn_def,TRUE);
+          gtk_window_set_default(dialog, btn_def);
+          g_object_set_data(PGObject(Dialog), 'modal_result',
+            {%H-}Pointer(PtrInt(BtnID)));
+        end;
+
+        inc(BtnIdx);
+      end;
+    end;
+    ChildList:=ChildList^.prev;
+  end;
+  if MainList <> nil then
+    g_list_free(MainList);
+
+end;
+
+procedure TGtk3DialogFactory.run;
+var
+  Title:string;
+begin
+  if not Assigned(Dialog) then exit;
+
+  if fCaption <> '' then
+    Title:=fCaption
+  else
+  begin
+    Title := '';
+    case fDialogType of
+      idDialogWarning: Title := rsMtWarning;
+      idDialogError: Title := rsMtError;
+      idDialogInfo : Title := rsMtInformation;
+      idDialogConfirm : Title := rsMtConfirmation;
+    end;
+  end;
+
+  gtk_window_set_title(PGtkWindow(Dialog), PGChar(Title));
+  gtk_dialog_run(Dialog);
+  Self.DialogResult:=Self.gtk_resp_to_lcl(Self.DialogResult);
+end;
+
+class function TGtk3DialogFactory.tr(UseWidgetStr: boolean; const TranslatedStr, WidgetStr: String): string;
+begin
+  if UseWidgetStr then
+    Result:=WidgetStr
+  else
+    Result:=TranslatedStr;
+end;
+
+destructor TGtk3DialogFactory.Destroy;
+begin
+  if Assigned(Dialog) then
+  gtk_widget_destroy(Dialog);
+end;
+
+
+constructor TGtk3DialogFactory.CreatePrompt(const DialogCaption,
+  DialogMessage: string; DialogType: LongInt; Buttons: PLongInt;
+  ButtonCount: LongInt; DefaultIndex: LongInt; EscapeResult: LongInt);
+var
+  x,i:integer;
+  GtkDialogType: TGtkMessageType;
+  Btns: TGtkButtonsType;
+  DefaultID: Integer;
+begin
+  DialogResult := EscapeResult;
+  fDialogType := DialogType;
+  GtkDialogType := MessageType(fDialogType); // map LCLINTF -> GTK
+  pButtons:=Buttons;
+  fCaption:=DialogCaption;
+
+  Btns := GTK_BUTTONS_NONE;
+  DefaultId := 0;
+  for X := 0 to ButtonCount - 1 do
+  begin
+    if X = DefaultIndex then
+      DefaultID := Buttons[X];
+  end;
+
+  Dialog := gtk_message_dialog_new(nil, GTK_DIALOG_MODAL, GtkDialogType, Btns, nil , []);
+
+  gtk_message_dialog_set_markup(PGtkMessageDialog(Dialog), PGChar(DialogMessage));
+
+  g_signal_connect_data(GPointer(Dialog), 'delete-event',
+    TGCallback(@BoxClosed),
+    @DialogResult, nil, 0);
+
+  if Btns = GTK_BUTTONS_NONE then
+  begin
+    for i := ButtonCount-1 downto 0 do
+    begin
+      case Buttons[i] of
+        idButtonOK       : CreateButton(tr(rsmbOK='&OK',rsmbOK, 'gtk-ok'), GTK_RESPONSE_OK);
+        idButtonCancel   : CreateButton(tr(rsmbCancel='Cancel',rsmbCancel,'gtk-cancel'), GTK_RESPONSE_CANCEL);
+        idButtonHelp     : CreateButton(tr(rsmbHelp='&Help',rsmbHelp,'gtk-help'), GTK_RESPONSE_HELP);
+        idButtonYes      : CreateButton(tr(rsmbYes='&Yes',rsmbYes,'gtk-yes'), GTK_RESPONSE_YES);
+        idButtonNo       : CreateButton(tr(rsmbNo='&No',rsmbNo,'gtk-no'), GTK_RESPONSE_NO);
+        idButtonClose    : CreateButton(tr(rsmbClose='&Close',rsmbClose,'gtk-close'), GTK_RESPONSE_CLOSE);
+        idButtonAbort    : CreateButton(rsMBAbort, GTK_RESPONSE_REJECT);
+        idButtonRetry    : CreateButton(rsMBRetry, GTK_RESPONSE_LCL_RETRY);
+        idButtonIgnore   : CreateButton(rsMBIgnore, GTK_RESPONSE_LCL_IGNORE);
+        idButtonAll      : CreateButton(rsMbAll, GTK_RESPONSE_LCL_ALL);
+        idButtonNoToAll  : CreateButton(rsMBNoToAll, GTK_RESPONSE_LCL_NOTOALL);
+        idButtonYesToAll : CreateButton(rsMBYesToAll, GTK_RESPONSE_LCL_YESTOALL);
+      end;
+    end;
+  end;
+  update_widget_list(@btn_ptr_info);
+end;
+
+
+constructor TGtk3DialogFactory.CreateMsgBox1(hWnd: HWND; lpText, lpCaption: PChar;
+  uType: Cardinal);
+var
+  ALabel : PGtkWidget;
+  ButtonCount, DefButton : Integer;
+(*  procedure CreateButton(const ALabel : PChar; const RetValue : integer);
+  var AButton : PGtkWidget;
+  begin
+    AButton:= gtk_button_new_with_label(ALabel);
+    Inc(ButtonCount);
+    if ButtonCount = DefButton then begin
+      gtk_window_set_focus(PGtkWindow(Dialog), AButton);
+    end;
+    { If there is the Cancel button, allow the dialog to close }
+    if RetValue = IDCANCEL then begin
+      g_object_set_data(PGObject(Dialog), 'modal_result', Pointer(IDCANCEL));
+    end;
+    g_object_set_data(AButton, 'modal_result',
+                        {%H-}Pointer(PtrInt(RetValue)));
+    g_signal_connect_data(AButton, 'clicked',
+                     TGCallback(@MessageButtonClicked), GPointer(@ADialogResult), nil, 0);
+    gtk_container_add (PGtkContainer(PGtkDialog(Dialog)^.get_action_area), AButton);
+  end;*)
+
+begin
+  ButtonCount:= 0;
+
+  fCaption:=lpCaption;
+  { Determine which is the default button }
+  DefButton:= ((uType and $00000300) shr 8) + 1;
+  //DebugLn('Trace:Default button is ' + IntToStr(DefButton));
+
+  DialogResult:= 0;
+  Dialog := gtk_dialog_new;
+  g_signal_connect_data(Dialog, 'delete-event', TGCallback(@BoxClosed), @DialogResult, nil, 0);
+  gtk_window_set_default_size(PGtkWindow(Dialog), 100, 100);
+  ALabel:= gtk_label_new(lpText);
+  gtk_container_add (PGtkContainer(PGtkDialog(Dialog)^.get_content_area), ALabel);
+  fDialogType:= (uType and $0000000F);
+  if fDialogType = MB_OKCANCEL
+  then begin
+    CreateButton(PChar(rsMbOK), IDOK);
+    CreateButton(PChar(rsMbCancel), IDCANCEL);
+  end
+  else begin
+    if fDialogType = MB_ABORTRETRYIGNORE
+    then begin
+      CreateButton(PChar(rsMbAbort), IDABORT);
+      CreateButton(PChar(rsMbRetry), IDRETRY);
+      CreateButton(PChar(rsMbIgnore), IDIGNORE);
+    end
+    else begin
+      if fDialogType = MB_YESNOCANCEL
+      then begin
+        CreateButton(PChar(rsMbYes), IDYES);
+        CreateButton(PChar(rsMbNo), IDNO);
+        CreateButton(PChar(rsMbCancel), IDCANCEL);
+      end
+      else begin
+        if fDialogType = MB_YESNO
+        then begin
+          CreateButton(PChar(rsMbYes), IDYES);
+          CreateButton(PChar(rsMbNo), IDNO);
+        end
+        else begin
+          if fDialogType = MB_RETRYCANCEL
+          then begin
+            CreateButton(PChar(rsMbRetry), IDRETRY);
+            CreateButton(PChar(rsMbCancel), IDCANCEL);
+          end
+          else begin
+            { We have no buttons to show. Create the default of OK button }
+            CreateButton(PChar(rsMbOK), IDOK);
+          end;
+        end;
+      end;
+    end;
+  end;
+  gtk_window_set_title(PGtkWindow(Dialog), lpCaption);
+  gtk_window_set_position(PGtkWindow(Dialog), GTK_WIN_POS_CENTER);
+  gtk_window_set_modal(PGtkWindow(Dialog), true);
+  gtk_widget_show_all(Dialog);
+end;
+
+constructor TGtk3DialogFactory.CreateMsgBox(hWnd: HWND; lpText,
+  lpCaption: PChar; uType: Cardinal);
+var
+  ADialogType:integer;
+  btns:array of integer;
+
+  procedure AddBtn(btn_res:integer);
+  begin
+    setlength(btns,length(btns)+1);
+    btns[high(btns)]:=btn_res;
+  end;
+
+begin
+  ADialogType:= (uType and $0000000F);
+  if ADialogType = MB_OKCANCEL
+  then begin
+    AddBtn(idButtonOk);
+    AddBtn(idButtonCancel);
+  end
+  else begin
+    if ADialogType = MB_ABORTRETRYIGNORE
+    then begin
+      AddBtn(idButtonAbort);
+      AddBtn(idButtonRetry);
+      AddBtn(idButtonIgnore);
+    end
+    else begin
+      if ADialogType = MB_YESNOCANCEL
+      then begin
+        AddBtn(idButtonYes);
+        AddBtn(idButtonNo);
+        AddBtn(idButtonCancel);
+      end
+      else begin
+        if ADialogType = MB_YESNO
+        then begin
+          AddBtn(idButtonYes);
+          AddBtn(idButtonNo);
+        end
+        else begin
+          if ADialogType = MB_RETRYCANCEL
+          then begin
+            AddBtn(idButtonRetry);
+            AddBtn(idButtonCancel);
+          end
+          else begin
+            { We have no buttons to show. Create the default of OK button }
+            AddBtn(idButtonOK);
+          end;
+        end;
+      end;
+    end;
+  end;
+  Self.CreatePrompt(lpCaption,lpText,0,@btns[0],length(btns),0,0);
+end;
+
+
+end.
+
Index: lcl/interfaces/gtk3/gtk3int.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3int.pas	(revision 63598)
+++ lcl/interfaces/gtk3/gtk3int.pas	(working copy)
@@ -151,16 +151,9 @@
 
 implementation
 uses
-  Math, LCLMessageGlue,
+  Math, LCLMessageGlue, gtk3boxes,
   {%H-}Gtk3WSFactory{%H-};
 
-const
-  GTK_RESPONSE_LCL_ALL = -10;
-  GTK_RESPONSE_LCL_YESTOALL = -3; // GTK_RESPONSE_ACCEPT;
-  GTK_RESPONSE_LCL_RETRY = -12;
-  GTK_RESPONSE_LCL_IGNORE = -13;
-  GTK_RESPONSE_LCL_NOTOALL = -14;
-
 {------------------------------------------------------------------------------
   Function: FillStandardDescription
   Params:
Index: lcl/interfaces/gtk3/gtk3lclintf.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3lclintf.inc	(revision 63598)
+++ lcl/interfaces/gtk3/gtk3lclintf.inc	(working copy)
@@ -1054,337 +1054,6 @@
     Result := nil;
 end;
 
-function PromptUserBoxClosed(Widget : PGtkWidget; {%H-}Event : PGdkEvent;
-  data: gPointer) : GBoolean; cdecl;
-var
-  ModalResult : PtrUInt;
-begin
-  { We were requested by window manager to close so return EscapeResult}
-  if PInteger(data)^ = 0 then
-  begin
-    ModalResult:= {%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
-    { Don't allow to close if we don't have a default return value }
-    Result:= (ModalResult = 0);
-    if not Result then PInteger(data)^:= ModalResult
-    else DebugLn('Do not close !!!');
-  end else Result:= false;
-end;
-
-function PromptUserButtonClicked(Widget : PGtkWidget; data: gPointer) : GBoolean; cdecl;
-begin
-  PInteger(data)^ := {%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
-  Result := False;
-end;
-
-
-type
-  TBtnListfunction=function(ndx:integer):longint of object;
-  TGtk3DialogFactory = class
-    btn_def: PGtkButton;
-    DefaultNdx: Integer;
-    fButtons: TDialogButtons;
-    pButtons: PLongint;
-    fCaption: string;
-    fDialogType:longint;
-    Dialog: PGtkMessageDialog;
-    DialogResult: Integer;
-    constructor CreateAsk(const DialogCaption, DialogMessage: string;
-       DialogType: LongInt; Buttons: TDialogButtons; HelpCtx: Longint);
-    constructor CreatePrompt(const DialogCaption, DialogMessage: string;
-       DialogType: LongInt; Buttons: PLongInt;
-       ButtonCount: LongInt; DefaultIndex: LongInt; EscapeResult: LongInt);
-    class function tr(UseWidgetStr: boolean; const TranslatedStr, WidgetStr: String): string;
-    destructor Destroy;override;
-    procedure run;
-    function btn_coll_info(ndx:integer):longint;
-    function btn_ptr_info(ndx:integer):longint;
-    procedure update_widget_list(const func:TBtnListFunction);
-    procedure CreateButton(const ALabel : String; const AResponse: Integer;
-      const AImageHint: Integer = -1);
-    class function ResponseID(const AnID: Integer): Integer;
-    class function gtk_resp_to_lcl(const gtk_resp:integer):integer;
-    class function MessageType(ADialogType:longint):TGtkMessageType;
-  end;
-
-class function TGtk3DialogFactory.ResponseID(const AnID: Integer): Integer;
-begin
-  case AnID of
-    idButtonOK       : Result := GTK_RESPONSE_OK;
-    idButtonCancel   : Result := GTK_RESPONSE_CANCEL;
-    idButtonHelp     : Result := GTK_RESPONSE_HELP;
-    idButtonYes      : Result := GTK_RESPONSE_YES;
-    idButtonNo       : Result := GTK_RESPONSE_NO;
-    idButtonClose    : Result := GTK_RESPONSE_CLOSE;
-    idButtonAbort    : Result := GTK_RESPONSE_REJECT;
-    idButtonRetry    : Result := GTK_RESPONSE_LCL_RETRY;
-    idButtonIgnore   : Result := GTK_RESPONSE_LCL_IGNORE;
-    idButtonAll      : Result := GTK_RESPONSE_LCL_ALL;
-    idButtonNoToAll  : Result := GTK_RESPONSE_LCL_NOTOALL;
-    idButtonYesToAll : Result := GTK_RESPONSE_LCL_YESTOALL;
-  else
-    Result:=AnID;
-  end;
-end;
-
-
-class function TGtk3DialogFactory.gtk_resp_to_lcl(const gtk_resp:integer):integer;
-begin
-  case gtk_resp of
-  -5{GTK_RESPONSE_OK}: Result:=  mrOK;
-  -6{GTK_RESPONSE_CANCEL}:  Result := mrCancel;
-  -7{GTK_RESPONSE_CLOSE}: Result:=mrClose;
-  -8{GTK_RESPONSE_YES}: Result:=mrYes;
-  -9{GTK_RESPONSE_NO}: Result:=mrNo;
-  -10{GTK_RESPONSE_APPLY}: Result:=mrAll;
-//  -11{GTK_RESPONSE_HELP}: Result:=mrhelp;
-
-  -1{GTK_RESPONSE_NONE}: Result:=mrNone;
-  -2{GTK_RESPONSE_REJECT}: Result:=mrAbort;
-  -3{GTK_RESPONSE_ACCEPT}: Result:=mrAll;
-  else
-    Result:=gtk_resp;
-  end;
-end;
-
-procedure TGtk3DialogFactory.CreateButton(
-    const ALabel : String;
-    const AResponse: Integer;
-    const AImageHint: Integer = -1);
-var
-  NewButton: PGtkWidget;
-  //BitmapHandle, MaskHandle: HBitmap;
-  // GDIObject: PGDIObject;
-  //Pixbuf: PGdkPixbuf;
-  // Mask: PGdkBitmap;
-  //Img: PGtkWidget;
-begin
-
-  NewButton := gtk_dialog_add_button(Dialog,
-    PgChar({Ampersands2Underscore}(ALabel)), AResponse);
-  gtk_button_set_use_underline(PGtkButton(NewButton), True);
-  g_object_set_data(PGObject(NewButton), 'modal_result',
-        {%H-}Pointer(PtrInt(AResponse)));
-  (*
-  if AImageHint >= 0 then
-  begin
-    if ThemeServices.GetStockImage(AImageHint, BitmapHandle, MaskHandle) then
-    begin
-      GDIObject := {%H-}PGDIObject(BitmapHandle);
-      Mask := nil;
-      Pixbuf := nil;
-      if GDIObject^.GDIBitmapType = gbPixbuf then
-        Pixbuf := GDIObject^.GDIPixbufObject
-      else
-        Mask := CreateGdkMaskBitmap(BitmapHandle, MaskHandle);
-
-      Img := gtk_image_new;
-
-      if Pixbuf <> nil then
-        gtk_image_set_from_pixbuf(PGtkImage(Img), Pixbuf)
-      else
-        gtk_image_set_from_pixmap(PGtkImage(Img), GDIObject^.GDIPixmapObject.Image, Mask);
-      gtk_button_set_image(PGtkButton(NewButton), Img);
-      if Mask <> nil then
-        g_object_unref(Mask);
-      DeleteObject(BitmapHandle);
-      DeleteObject(MaskHandle);
-    end;
-  end;
-  *)
-end;
-
-class function TGtk3DialogFactory.MessageType(ADialogType:longint):TGtkMessageType;
-begin
-  case ADialogType of
-    idDialogWarning: Result := GTK_MESSAGE_WARNING;
-    idDialogError: Result := GTK_MESSAGE_ERROR;
-    idDialogInfo : Result := GTK_MESSAGE_INFO;
-    idDialogConfirm : Result := GTK_MESSAGE_QUESTION;
-  else
-    Result := GTK_MESSAGE_INFO;
-  end;
-end;
-
-
-const
-  ButtonResults : array[mrNone..mrYesToAll] of Longint = (
-    -1, idButtonOK, idButtonCancel, idButtonAbort, idButtonRetry,
-    idButtonIgnore, idButtonYes,idButtonNo, idButtonAll, idButtonNoToAll,
-    idButtonYesToAll);
-
-constructor TGtk3DialogFactory.CreateAsk(const DialogCaption,
-       DialogMessage: string; DialogType: LongInt;
-       Buttons: TDialogButtons; HelpCtx: Longint);
-var
-  GtkDialogType: TGtkMessageType;
-  Btns: TGtkButtonsType;
-  i, BtnIdx, BtnID: Integer;
-  dbtn:TDialogButton;
-  Title: String;
-  BtnResult: LongInt;
-begin
-  DialogResult := mrNone;
-  fDialogType := DialogType;
-  GtkDialogType := MessageType(fDialogType); // map LCLINTF -> GTK
-  fButtons:=Buttons;
-  fCaption:=DialogCaption;
-
-  Btns := GTK_BUTTONS_NONE;
-  DefaultNdx := 0;
-  for i := 0 to Buttons.Count - 1 do
-  begin
-    if Buttons[i].Default then
-      DefaultNdx := i;
-
-    if (DialogResult = mrNone) and
-      (Buttons[i].ModalResult in [mrCancel, mrAbort, mrIgnore, mrNo, mrNoToAll])
-    then
-      DialogResult := Buttons[i].ModalResult;
-  end;
-
-  Dialog := gtk_message_dialog_new(nil, GTK_DIALOG_MODAL, GtkDialogType, Btns, nil , []);
-
-  gtk_message_dialog_set_markup(PGtkMessageDialog(Dialog), PGChar(DialogMessage));
-
-  g_signal_connect_data(Dialog, 'delete-event',
-    TGCallback(@PromptUserBoxClosed),
-    @DialogResult, nil, 0);
-
-  if Btns = GTK_BUTTONS_NONE then
-  begin
-    // gtk3 have reverted buttons eg. No, Yes
-    for BtnIdx := Buttons.Count - 1 downto 0 do
-    begin
-      dbtn:=Buttons[BtnIdx];
-      if (dbtn.ModalResult >= Low(ButtonResults)) and (dbtn.ModalResult <= High(ButtonResults)) then
-      begin
-        BtnID := ButtonResults[dbtn.ModalResult];
-        case BtnID of
-          idButtonOK       : CreateButton(dbtn.Caption, GTK_RESPONSE_OK, BtnID);
-          idButtonCancel   : CreateButton(dbtn.Caption, GTK_RESPONSE_CANCEL, BtnID);
-          idButtonHelp     : CreateButton(dbtn.Caption, GTK_RESPONSE_HELP, BtnID);
-          idButtonYes      : CreateButton(dbtn.Caption, GTK_RESPONSE_YES, BtnID);
-          idButtonNo       : CreateButton(dbtn.Caption, GTK_RESPONSE_NO, BtnID);
-          idButtonClose    : CreateButton(dbtn.Caption, GTK_RESPONSE_CLOSE, BtnID);
-          idButtonAbort    : CreateButton(dbtn.Caption, GTK_RESPONSE_REJECT, BtnID);
-          idButtonRetry    : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_RETRY, BtnID);
-          idButtonIgnore   : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_IGNORE, BtnID);
-          idButtonAll      : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_ALL, BtnID);
-          idButtonNoToAll  : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_NOTOALL, BtnID);
-          idButtonYesToAll : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_YESTOALL, BtnID);
-        end;
-      end else
-         CreateButton(dbtn.Caption, dbtn.ModalResult, 0);
-
-    end;
-  end;
-
-  update_widget_list(@btn_coll_info);
-
-end;
-
-
-function TGtk3DialogFactory.btn_coll_info(ndx:integer):longint;
-begin
-  Result:=fButtons[ndx].ModalResult; // get modal result for button
-end;
-
-function TGtk3DialogFactory.btn_ptr_info(ndx:integer):longint;
-begin
-  Result:=pButtons[ndx];
-end;
-
-procedure TGtk3DialogFactory.update_widget_list(const func:TBtnListFunction);
-var
-  btn:PgtkButton;
-  BtnIdx,BtnID,BtnRes:integer;
-  MainList,ChildList: PGList;
-begin
-  MainList := gtk_container_get_children(PGtkContainer(Dialog^.get_action_area));
-  ChildList:=g_list_last(MainList);
-  BtnIdx:=0;
-  btn_def:=nil;
-  while Assigned(ChildList) do
-  begin
-    if (ChildList^.Data <> nil) then
-    begin
-      if g_type_check_instance_is_a(ChildList^.Data, gtk_button_get_type) then
-      begin
-        Btn := PGtkButton(ChildList^.Data);
-
-        BtnRes:=func(BtnIdx); // process button
-
-        if (BtnRes>=Low(ButtonResults)) and (BtnRes<=High(ButtonResults)) then
-          BtnID := ButtonResults[BtnRes]
-        else
-          BtnID := BtnRes;
-
-        if BtnID = idButtonCancel then
-           g_object_set_data(PGObject(Dialog), 'modal_result', Pointer(idButtonCancel));
-
-        g_signal_connect_data(Btn, 'clicked',
-          TGCallback(@PromptUserButtonClicked), @DialogResult, nil, 0);
-
-        if DefaultNdx = BtnIdx then
-        begin
-          gtk_dialog_set_default_response(Dialog, ResponseID(BtnID));
-          btn_def:=btn;
-          gtk_widget_grab_default(btn);
-          gtk_widget_grab_focus(btn);
-          gtk_widget_set_can_default(btn_def,TRUE);
-          gtk_window_set_default(dialog, btn_def);
-          g_object_set_data(PGObject(Dialog), 'modal_result',
-            {%H-}Pointer(PtrInt(BtnID)));
-        end;
-
-        inc(BtnIdx);
-      end;
-    end;
-    ChildList:=ChildList^.prev;
-  end;
-  if MainList <> nil then
-    g_list_free(MainList);
-
-end;
-
-procedure TGtk3DialogFactory.run;
-var
-  Title:string;
-begin
-  if not Assigned(Dialog) then exit;
-
-  if fCaption <> '' then
-    Title:=fCaption
-  else
-  begin
-    Title := '';
-    case fDialogType of
-      idDialogWarning: Title := rsMtWarning;
-      idDialogError: Title := rsMtError;
-      idDialogInfo : Title := rsMtInformation;
-      idDialogConfirm : Title := rsMtConfirmation;
-    end;
-  end;
-
-  gtk_window_set_title(PGtkWindow(Dialog), PGChar(Title));
-  gtk_dialog_run(Dialog);
-  Self.DialogResult:=Self.gtk_resp_to_lcl(Self.DialogResult);
-end;
-
-class function TGtk3DialogFactory.tr(UseWidgetStr: boolean; const TranslatedStr, WidgetStr: String): string;
-begin
-  if UseWidgetStr then
-    Result:=WidgetStr
-  else
-    Result:=TranslatedStr;
-end;
-
-destructor TGtk3DialogFactory.Destroy;
-begin
-  if Assigned(Dialog) then
-  gtk_widget_destroy(Dialog);
-end;
-
 function TGtk3WidgetSet.AskUser(const DialogCaption, DialogMessage: string; DialogType:
    LongInt; Buttons: TDialogButtons; HelpCtx: Longint): LongInt;
 var
@@ -1416,60 +1085,7 @@
 
 end;
 
-constructor TGtk3DialogFactory.CreatePrompt(const DialogCaption: string;
-     const DialogMessage: string; DialogType: LongInt; Buttons: PLongInt;
-    ButtonCount: LongInt; DefaultIndex: LongInt; EscapeResult: LongInt);
-var
-  x,i:integer;
-  GtkDialogType: TGtkMessageType;
-  Btns: TGtkButtonsType;
-  DefaultID: Integer;
-begin
-  DialogResult := EscapeResult;
-  fDialogType := DialogType;
-  GtkDialogType := MessageType(fDialogType); // map LCLINTF -> GTK
-  pButtons:=Buttons;
-  fCaption:=DialogCaption;
 
-  Btns := GTK_BUTTONS_NONE;
-  DefaultId := 0;
-  for X := 0 to ButtonCount - 1 do
-  begin
-    if X = DefaultIndex then
-      DefaultID := Buttons[X];
-  end;
-
-  Dialog := gtk_message_dialog_new(nil, GTK_DIALOG_MODAL, GtkDialogType, Btns, nil , []);
-
-  gtk_message_dialog_set_markup(PGtkMessageDialog(Dialog), PGChar(DialogMessage));
-
-  g_signal_connect_data(GPointer(Dialog), 'delete-event',
-    TGCallback(@PromptUserBoxClosed),
-    @DialogResult, nil, 0);
-
-  if Btns = GTK_BUTTONS_NONE then
-  begin
-    for i := ButtonCount-1 downto 0 do
-    begin
-      case Buttons[i] of
-        idButtonOK       : CreateButton(tr(rsmbOK='&OK',rsmbOK, 'gtk-ok'), GTK_RESPONSE_OK);
-        idButtonCancel   : CreateButton(tr(rsmbCancel='Cancel',rsmbCancel,'gtk-cancel'), GTK_RESPONSE_CANCEL);
-        idButtonHelp     : CreateButton(tr(rsmbHelp='&Help',rsmbHelp,'gtk-help'), GTK_RESPONSE_HELP);
-        idButtonYes      : CreateButton(tr(rsmbYes='&Yes',rsmbYes,'gtk-yes'), GTK_RESPONSE_YES);
-        idButtonNo       : CreateButton(tr(rsmbNo='&No',rsmbNo,'gtk-no'), GTK_RESPONSE_NO);
-        idButtonClose    : CreateButton(tr(rsmbClose='&Close',rsmbClose,'gtk-close'), GTK_RESPONSE_CLOSE);
-        idButtonAbort    : CreateButton(rsMBAbort, GTK_RESPONSE_REJECT);
-        idButtonRetry    : CreateButton(rsMBRetry, GTK_RESPONSE_LCL_RETRY);
-        idButtonIgnore   : CreateButton(rsMBIgnore, GTK_RESPONSE_LCL_IGNORE);
-        idButtonAll      : CreateButton(rsMbAll, GTK_RESPONSE_LCL_ALL);
-        idButtonNoToAll  : CreateButton(rsMBNoToAll, GTK_RESPONSE_LCL_NOTOALL);
-        idButtonYesToAll : CreateButton(rsMBYesToAll, GTK_RESPONSE_LCL_YESTOALL);
-      end;
-    end;
-  end;
-  update_widget_list(@btn_ptr_info);
-end;
-
 function TGtk3WidgetSet.SetComboMinDropDownSize(Handle: HWND; MinItemsWidth,
   MinItemsHeight, MinItemCount: integer): boolean;
 var
Index: lcl/interfaces/gtk3/gtk3winapi.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 63598)
+++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
@@ -2961,116 +2961,18 @@
   Result:=true;
 end;
 
-function MessageButtonClicked(Widget : PGtkWidget; data: gPointer) : GBoolean; cdecl;
-begin
-  //DebugLn('[MessageButtonClicked] ',dbgs(data),' ',dbgs(g_object_get_data(PGtkObject(Widget), 'modal_result')));
-  if PInteger(data)^ = 0 then
-    PInteger(data)^:={%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
-  Result:=false;
-end;
-
-function MessageBoxClosed(Widget : PGtkWidget; {%H-}Event : PGdkEvent;
-  data: gPointer) : GBoolean; cdecl;
-var ModalResult : PtrUInt;
-begin
-  { We were requested by window manager to close }
-  if PInteger(data)^ = 0 then begin
-    ModalResult:= {%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
-    { Don't allow to close if we don't have a default return value }
-    Result:= (ModalResult = 0);
-    if not Result then PInteger(data)^:= ModalResult
-    else DebugLn('Do not close !!!');
-  end else Result:= false;
-end;
-
 function TGtk3WidgetSet.MessageBox(hWnd: HWND; lpText, lpCaption: PChar;
   uType: Cardinal): integer;
 var
-  Dialog, ALabel : PGtkWidget;
-  ButtonCount, DefButton, ADialogResult : Integer;
-  DialogType : Cardinal;
-  procedure CreateButton(const ALabel : PChar; const RetValue : integer);
-  var AButton : PGtkWidget;
-  begin
-    AButton:= gtk_button_new_with_label(ALabel);
-    Inc(ButtonCount);
-    if ButtonCount = DefButton then begin
-      gtk_window_set_focus(PGtkWindow(Dialog), AButton);
-    end;
-    { If there is the Cancel button, allow the dialog to close }
-    if RetValue = IDCANCEL then begin
-      g_object_set_data(PGObject(Dialog), 'modal_result', Pointer(IDCANCEL));
-    end;
-    g_object_set_data(AButton, 'modal_result',
-                        {%H-}Pointer(PtrInt(RetValue)));
-    g_signal_connect_data(AButton, 'clicked',
-                     TGCallback(@MessageButtonClicked), GPointer(@ADialogResult), nil, 0);
-    gtk_container_add (PGtkContainer(PGtkDialog(Dialog)^.get_action_area), AButton);
-  end;
-
+  fact:TGtk3DialogFactory;
 begin
-  ButtonCount:= 0;
-  { Determine which is the default button }
-  DefButton:= ((uType and $00000300) shr 8) + 1;
-  //DebugLn('Trace:Default button is ' + IntToStr(DefButton));
-
-  ADialogResult:= 0;
-  Dialog:= gtk_dialog_new;
-  g_signal_connect_data(Dialog, 'delete-event', TGCallback(@MessageBoxClosed), @ADialogResult, nil, 0);
-  gtk_window_set_default_size(PGtkWindow(Dialog), 100, 100);
-  ALabel:= gtk_label_new(lpText);
-  gtk_container_add (PGtkContainer(PGtkDialog(Dialog)^.get_content_area), ALabel);
-  DialogType:= (uType and $0000000F);
-  if DialogType = MB_OKCANCEL
-  then begin
-    CreateButton(PChar(rsMbOK), IDOK);
-    CreateButton(PChar(rsMbCancel), IDCANCEL);
-  end
-  else begin
-    if DialogType = MB_ABORTRETRYIGNORE
-    then begin
-      CreateButton(PChar(rsMbAbort), IDABORT);
-      CreateButton(PChar(rsMbRetry), IDRETRY);
-      CreateButton(PChar(rsMbIgnore), IDIGNORE);
-    end
-    else begin
-      if DialogType = MB_YESNOCANCEL
-      then begin
-        CreateButton(PChar(rsMbYes), IDYES);
-        CreateButton(PChar(rsMbNo), IDNO);
-        CreateButton(PChar(rsMbCancel), IDCANCEL);
-      end
-      else begin
-        if DialogType = MB_YESNO
-        then begin
-          CreateButton(PChar(rsMbYes), IDYES);
-          CreateButton(PChar(rsMbNo), IDNO);
-        end
-        else begin
-          if DialogType = MB_RETRYCANCEL
-          then begin
-            CreateButton(PChar(rsMbRetry), IDRETRY);
-            CreateButton(PChar(rsMbCancel), IDCANCEL);
-          end
-          else begin
-            { We have no buttons to show. Create the default of OK button }
-            CreateButton(PChar(rsMbOK), IDOK);
-          end;
-        end;
-      end;
-    end;
+  fact:=TGtk3DialogFactory.CreateMsgBox(hWnd,lpText,lpCaption,uType);
+  try
+    fact.run;
+    Result:=fact.DialogResult;
+  finally
+    fact.Free;
   end;
-  gtk_window_set_title(PGtkWindow(Dialog), lpCaption);
-  gtk_window_set_position(PGtkWindow(Dialog), GTK_WIN_POS_CENTER);
-  gtk_window_set_modal(PGtkWindow(Dialog), true);
-  gtk_widget_show_all(Dialog);
-  while ADialogResult = 0 do
-  begin
-    Application.HandleMessage;
-  end;
-  if Gtk3IsWidget(Dialog) then
-    gtk_widget_destroy(Dialog);
-  Result:= ADialogResult;
 end;
 
 function TGtk3WidgetSet.MonitorFromPoint(ptScreenCoords: TPoint; dwFlags: DWord
gtk3.diff (37,871 bytes)   

Anton Kavalenka

2020-07-20 15:39

reporter   ~0124188

Next step.
I clicked over all the flags. Looks like it is working.
Btw is somewhere documentation why MessageBox returns ID_YES but PromptUser returns idButtonYes.
gtk3-2.diff (39,813 bytes)   
Index: lcl/interfaces/gtk3/gtk3boxes.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3boxes.pas	(nonexistent)
+++ lcl/interfaces/gtk3/gtk3boxes.pas	(working copy)
@@ -0,0 +1,616 @@
+unit gtk3boxes;
+
+interface
+
+uses
+  lcltype,
+  interfacebase,
+  lazgtk3;
+
+type
+  TBtnListfunction=function(ndx:integer):longint of object;
+
+  { TGtk3DialogFactory }
+
+  TGtk3DialogFactory = class
+    btn_def: PGtkButton;
+    DefaultNdx: Integer;
+    fButtons: TDialogButtons;
+    pButtons: PLongint;
+    fCaption: string;
+    fDialogType:longint;
+    Dialog: PGtkDialog;
+    DialogResult: Integer;
+    constructor CreateAsk(const DialogCaption, DialogMessage: string;
+       DialogType: LongInt; Buttons: TDialogButtons; HelpCtx: Longint);
+    constructor CreatePrompt(const DialogCaption, DialogMessage: string;
+       DialogType: LongInt; Buttons: PLongInt;
+       ButtonCount: LongInt; DefaultIndex: LongInt; EscapeResult: LongInt);
+    constructor CreateMsgBox(hWnd: HWND; lpText, lpCaption: PChar;
+       uType: Cardinal);
+    constructor CreateMsgBox1(hWnd: HWND; lpText, lpCaption: PChar;
+       uType: Cardinal);
+    class function tr(UseWidgetStr: boolean; const TranslatedStr, WidgetStr: String): string;
+    destructor Destroy;override;
+    procedure run;
+    function btn_coll_info(ndx:integer):longint;
+    function btn_ptr_info(ndx:integer):longint;
+    procedure update_widget_list(const func:TBtnListFunction);
+    procedure CreateButton(const ALabel : String; const AResponse: Integer;
+      const AImageHint: Integer = -1);
+    function lcl_result:integer;
+    function btn_result:integer;
+    class function ResponseID(const AnID: Integer): Integer;
+    class function gtk_resp_to_lcl(const gtk_resp:integer):integer;
+    class function gtk_resp_to_btn(const gtk_resp:integer):integer;
+    class function MessageType(ADialogType:longint):TGtkMessageType;
+  end;
+
+
+implementation
+uses lclstrconsts,lclproc,uitypes,lazglib2,lazgobject2,lazgdk3,gtk3objects;
+
+// fake GTK button responses
+const
+  GTK_RESPONSE_LCL_ALL = -10;
+  GTK_RESPONSE_LCL_YESTOALL = -3; // GTK_RESPONSE_ACCEPT;
+  GTK_RESPONSE_LCL_RETRY = -12;
+  GTK_RESPONSE_LCL_IGNORE = -13;
+  GTK_RESPONSE_LCL_NOTOALL = -14;
+
+
+{ callbacks }
+function BoxClosed(Widget : PGtkWidget; {%H-}Event : PGdkEvent;
+  data: gPointer) : GBoolean; cdecl;
+var
+  ModalResult : PtrUInt;
+begin
+  { We were requested by window manager to close so return EscapeResult}
+  if PInteger(data)^ = 0 then
+  begin
+    ModalResult:= {%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
+    { Don't allow to close if we don't have a default return value }
+    Result:= (ModalResult = 0);
+    if not Result then PInteger(data)^:= ModalResult
+    else DebugLn('Do not close !!!');
+  end else Result:= false;
+end;
+
+function ButtonClicked(Widget : PGtkWidget; data: gPointer) : GBoolean; cdecl;
+begin
+  PInteger(data)^ := {%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
+  Result := False;
+end;
+
+
+
+class function TGtk3DialogFactory.ResponseID(const AnID: Integer): Integer;
+begin
+  case AnID of
+    idButtonOK       : Result := GTK_RESPONSE_OK;
+    idButtonCancel   : Result := GTK_RESPONSE_CANCEL;
+    idButtonHelp     : Result := GTK_RESPONSE_HELP;
+    idButtonYes      : Result := GTK_RESPONSE_YES;
+    idButtonNo       : Result := GTK_RESPONSE_NO;
+    idButtonClose    : Result := GTK_RESPONSE_CLOSE;
+    idButtonAbort    : Result := GTK_RESPONSE_REJECT;
+    idButtonRetry    : Result := GTK_RESPONSE_LCL_RETRY;
+    idButtonIgnore   : Result := GTK_RESPONSE_LCL_IGNORE;
+    idButtonAll      : Result := GTK_RESPONSE_LCL_ALL;
+    idButtonNoToAll  : Result := GTK_RESPONSE_LCL_NOTOALL;
+    idButtonYesToAll : Result := GTK_RESPONSE_LCL_YESTOALL;
+  else
+    Result:=AnID;
+  end;
+end;
+
+
+class function TGtk3DialogFactory.gtk_resp_to_lcl(const gtk_resp:integer):integer;
+begin
+  case gtk_resp of
+  -5{GTK_RESPONSE_OK}: Result:=  ID_OK;
+  -6{GTK_RESPONSE_CANCEL}:  Result := id_Cancel;
+  -7{GTK_RESPONSE_CLOSE}: Result:=id_Close;
+  -8{GTK_RESPONSE_YES}: Result:=id_Yes;
+  -9{GTK_RESPONSE_NO}: Result:=id_No;
+
+  -1{GTK_RESPONSE_NONE}: Result:=0;
+  -2{GTK_RESPONSE_REJECT}: Result:=id_abort;
+  -3{GTK_RESPONSE_ACCEPT}: Result:=id_Yes;
+
+  GTK_RESPONSE_LCL_RETRY: Result:=id_Retry;
+  GTK_RESPONSE_LCL_IGNORE:  Result:=id_Ignore;
+  GTK_RESPONSE_LCL_ALL:  Result:=idButtonAll;
+  GTK_RESPONSE_LCL_NOTOALL: Result:=idButtonNoToAll;
+  //GTK_RESPONSE_LCL_YESTOALL: Result:= idButtonYesToAll;
+  else
+    Result:=gtk_resp;
+  end;
+end;
+
+class function TGtk3DialogFactory.gtk_resp_to_btn(const gtk_resp:integer):integer;
+begin
+  case gtk_resp of
+  -5{GTK_RESPONSE_OK}: Result:=  idButtonOk;
+  -6{GTK_RESPONSE_CANCEL}:  Result := idButtonCancel;
+  -7{GTK_RESPONSE_CLOSE}: Result:=idButtonClose;
+  -8{GTK_RESPONSE_YES}: Result:=idButtonYes;
+  -9{GTK_RESPONSE_NO}: Result:=idButtonNo;
+
+  -1{GTK_RESPONSE_NONE}: Result:=0;
+  -2{GTK_RESPONSE_REJECT}: Result:=idButtonAbort;
+  -3{GTK_RESPONSE_ACCEPT}: Result:=idButtonYesToAll;
+
+  GTK_RESPONSE_LCL_RETRY: Result:=idButtonRetry;
+  GTK_RESPONSE_LCL_IGNORE:  Result:=idButtonIgnore;
+  GTK_RESPONSE_LCL_ALL:  Result:=idButtonAll;
+  GTK_RESPONSE_LCL_NOTOALL: Result:=idButtonNoToAll;
+  //GTK_RESPONSE_LCL_YESTOALL: Result:= idButtonYesToAll;
+  else
+    Result:=gtk_resp;
+  end;
+end;
+
+
+procedure TGtk3DialogFactory.CreateButton(
+    const ALabel : String;
+    const AResponse: Integer;
+    const AImageHint: Integer = -1);
+var
+  NewButton: PGtkWidget;
+  //BitmapHandle, MaskHandle: HBitmap;
+  // GDIObject: PGDIObject;
+  //Pixbuf: PGdkPixbuf;
+  // Mask: PGdkBitmap;
+  //Img: PGtkWidget;
+begin
+
+  NewButton := gtk_dialog_add_button(Dialog,
+    PgChar(ReplaceAmpersandsWithUnderscores(ALabel)), AResponse);
+  gtk_button_set_use_underline(PGtkButton(NewButton), True);
+  g_object_set_data(PGObject(NewButton), 'modal_result',
+        {%H-}Pointer(PtrInt(AResponse)));
+  (*
+  if AImageHint >= 0 then
+  begin
+    if ThemeServices.GetStockImage(AImageHint, BitmapHandle, MaskHandle) then
+    begin
+      GDIObject := {%H-}PGDIObject(BitmapHandle);
+      Mask := nil;
+      Pixbuf := nil;
+      if GDIObject^.GDIBitmapType = gbPixbuf then
+        Pixbuf := GDIObject^.GDIPixbufObject
+      else
+        Mask := CreateGdkMaskBitmap(BitmapHandle, MaskHandle);
+
+      Img := gtk_image_new;
+
+      if Pixbuf <> nil then
+        gtk_image_set_from_pixbuf(PGtkImage(Img), Pixbuf)
+      else
+        gtk_image_set_from_pixmap(PGtkImage(Img), GDIObject^.GDIPixmapObject.Image, Mask);
+      gtk_button_set_image(PGtkButton(NewButton), Img);
+      if Mask <> nil then
+        g_object_unref(Mask);
+      DeleteObject(BitmapHandle);
+      DeleteObject(MaskHandle);
+    end;
+  end;
+  *)
+end;
+
+function TGtk3DialogFactory.lcl_result: integer;
+begin
+  Result:=gtk_resp_to_lcl(DialogResult);
+end;
+
+function TGtk3DialogFactory.btn_result: integer;
+begin
+  Result:=gtk_resp_to_btn(DialogResult);
+end;
+
+class function TGtk3DialogFactory.MessageType(ADialogType:longint):TGtkMessageType;
+begin
+  case ADialogType of
+    idDialogWarning: Result := GTK_MESSAGE_WARNING;
+    idDialogError: Result := GTK_MESSAGE_ERROR;
+    idDialogInfo : Result := GTK_MESSAGE_INFO;
+    idDialogConfirm : Result := GTK_MESSAGE_QUESTION;
+  else
+    Result := GTK_MESSAGE_INFO;
+  end;
+end;
+
+
+const
+  ButtonResults : array[mrNone..mrYesToAll] of Longint = (
+    -1, idButtonOK, idButtonCancel, idButtonAbort, idButtonRetry,
+    idButtonIgnore, idButtonYes,idButtonNo, idButtonAll, idButtonNoToAll,
+    idButtonYesToAll);
+
+constructor TGtk3DialogFactory.CreateAsk(const DialogCaption,
+       DialogMessage: string; DialogType: LongInt;
+       Buttons: TDialogButtons; HelpCtx: Longint);
+var
+  GtkDialogType: TGtkMessageType;
+  Btns: TGtkButtonsType;
+  i, BtnIdx, BtnID: Integer;
+  dbtn:TDialogButton;
+  Title: String;
+  BtnResult: LongInt;
+begin
+  DialogResult := mrNone;
+  fDialogType := DialogType;
+  GtkDialogType := MessageType(fDialogType); // map LCLINTF -> GTK
+  fButtons:=Buttons;
+  fCaption:=DialogCaption;
+
+  Btns := GTK_BUTTONS_NONE;
+  DefaultNdx := 0;
+  for i := 0 to Buttons.Count - 1 do
+  begin
+    if Buttons[i].Default then
+      DefaultNdx := i;
+
+    if (DialogResult = mrNone) and
+      (Buttons[i].ModalResult in [mrCancel, mrAbort, mrIgnore, mrNo, mrNoToAll])
+    then
+      DialogResult := Buttons[i].ModalResult;
+  end;
+
+  Dialog := gtk_message_dialog_new(nil, GTK_DIALOG_MODAL, GtkDialogType, Btns, nil , []);
+
+  gtk_message_dialog_set_markup(PGtkMessageDialog(Dialog), PGChar(DialogMessage));
+
+  g_signal_connect_data(Dialog, 'delete-event',
+    TGCallback(@BoxClosed),
+    @DialogResult, nil, 0);
+
+  if Btns = GTK_BUTTONS_NONE then
+  begin
+    // gtk3 have reverted buttons eg. No, Yes
+    for BtnIdx := Buttons.Count - 1 downto 0 do
+    begin
+      dbtn:=Buttons[BtnIdx];
+      if (dbtn.ModalResult >= Low(ButtonResults)) and (dbtn.ModalResult <= High(ButtonResults)) then
+      begin
+        BtnID := ButtonResults[dbtn.ModalResult];
+        case BtnID of
+          idButtonOK       : CreateButton(dbtn.Caption, GTK_RESPONSE_OK, BtnID);
+          idButtonCancel   : CreateButton(dbtn.Caption, GTK_RESPONSE_CANCEL, BtnID);
+          idButtonHelp     : CreateButton(dbtn.Caption, GTK_RESPONSE_HELP, BtnID);
+          idButtonYes      : CreateButton(dbtn.Caption, GTK_RESPONSE_YES, BtnID);
+          idButtonNo       : CreateButton(dbtn.Caption, GTK_RESPONSE_NO, BtnID);
+          idButtonClose    : CreateButton(dbtn.Caption, GTK_RESPONSE_CLOSE, BtnID);
+          idButtonAbort    : CreateButton(dbtn.Caption, GTK_RESPONSE_REJECT, BtnID);
+          idButtonRetry    : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_RETRY, BtnID);
+          idButtonIgnore   : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_IGNORE, BtnID);
+          idButtonAll      : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_ALL, BtnID);
+          idButtonNoToAll  : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_NOTOALL, BtnID);
+          idButtonYesToAll : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_YESTOALL, BtnID);
+        end;
+      end else
+         CreateButton(dbtn.Caption, dbtn.ModalResult, 0);
+
+    end;
+  end;
+
+  update_widget_list(@btn_coll_info);
+
+end;
+
+
+function TGtk3DialogFactory.btn_coll_info(ndx:integer):longint;
+begin
+  Result:=fButtons[ndx].ModalResult; // get modal result for button
+end;
+
+function TGtk3DialogFactory.btn_ptr_info(ndx:integer):longint;
+begin
+  Result:=pButtons[ndx];
+end;
+
+procedure TGtk3DialogFactory.update_widget_list(const func:TBtnListFunction);
+var
+  btn:PgtkButton;
+  BtnIdx,BtnID,BtnRes:integer;
+  MainList,ChildList: PGList;
+begin
+  MainList := gtk_container_get_children(PGtkContainer(Dialog^.get_action_area));
+  ChildList:=g_list_last(MainList);
+  BtnIdx:=0;
+  btn_def:=nil;
+  while Assigned(ChildList) do
+  begin
+    if (ChildList^.Data <> nil) then
+    begin
+      if g_type_check_instance_is_a(ChildList^.Data, gtk_button_get_type) then
+      begin
+        Btn := PGtkButton(ChildList^.Data);
+
+        BtnRes:=func(BtnIdx); // process button
+
+        if (BtnRes>=Low(ButtonResults)) and (BtnRes<=High(ButtonResults)) then
+          BtnID := ButtonResults[BtnRes]
+        else
+          BtnID := BtnRes;
+
+        if BtnID = idButtonCancel then
+           g_object_set_data(PGObject(Dialog), 'modal_result', Pointer(idButtonCancel));
+
+        g_signal_connect_data(Btn, 'clicked',
+          TGCallback(@ButtonClicked), @DialogResult, nil, 0);
+
+        if DefaultNdx = BtnIdx then
+        begin
+          gtk_dialog_set_default_response(Dialog, ResponseID(BtnID));
+          btn_def:=btn;
+          gtk_widget_grab_default(btn);
+          gtk_widget_grab_focus(btn);
+          gtk_widget_set_can_default(btn_def,TRUE);
+          gtk_window_set_default(dialog, btn_def);
+          g_object_set_data(PGObject(Dialog), 'modal_result',
+            {%H-}Pointer(PtrInt(BtnID)));
+        end;
+
+        inc(BtnIdx);
+      end;
+    end;
+    ChildList:=ChildList^.prev;
+  end;
+  if MainList <> nil then
+    g_list_free(MainList);
+
+end;
+
+procedure TGtk3DialogFactory.run;
+var
+  Title:string;
+begin
+  if not Assigned(Dialog) then exit;
+
+  if fCaption <> '' then
+    Title:=fCaption
+  else
+  begin
+    Title := '';
+    case fDialogType of
+      idDialogWarning: Title := rsMtWarning;
+      idDialogError: Title := rsMtError;
+      idDialogInfo : Title := rsMtInformation;
+      idDialogConfirm : Title := rsMtConfirmation;
+    end;
+  end;
+
+  gtk_window_set_title(PGtkWindow(Dialog), PGChar(Title));
+  gtk_dialog_run(Dialog);
+end;
+
+class function TGtk3DialogFactory.tr(UseWidgetStr: boolean; const TranslatedStr, WidgetStr: String): string;
+begin
+  if UseWidgetStr then
+    Result:=WidgetStr
+  else
+    Result:=TranslatedStr;
+end;
+
+destructor TGtk3DialogFactory.Destroy;
+begin
+  if Assigned(Dialog) then
+  gtk_widget_destroy(Dialog);
+end;
+
+
+constructor TGtk3DialogFactory.CreatePrompt(const DialogCaption,
+  DialogMessage: string; DialogType: LongInt; Buttons: PLongInt;
+  ButtonCount: LongInt; DefaultIndex: LongInt; EscapeResult: LongInt);
+var
+  x,i:integer;
+  GtkDialogType: TGtkMessageType;
+  Btns: TGtkButtonsType;
+  DefaultID: Integer;
+begin
+  DialogResult := EscapeResult;
+  fDialogType := DialogType;
+  GtkDialogType := MessageType(fDialogType); // map LCLINTF -> GTK
+  pButtons:=Buttons;
+  fCaption:=DialogCaption;
+
+  Btns := GTK_BUTTONS_NONE;
+  DefaultId := 0;
+  for X := 0 to ButtonCount - 1 do
+  begin
+    if X = DefaultIndex then
+      DefaultID := Buttons[X];
+  end;
+
+  Dialog := gtk_message_dialog_new(nil, GTK_DIALOG_MODAL, GtkDialogType, Btns, nil , []);
+
+  gtk_message_dialog_set_markup(PGtkMessageDialog(Dialog), PGChar(DialogMessage));
+
+  g_signal_connect_data(GPointer(Dialog), 'delete-event',
+    TGCallback(@BoxClosed),
+    @DialogResult, nil, 0);
+
+  if Btns = GTK_BUTTONS_NONE then
+  begin
+    for i := ButtonCount-1 downto 0 do
+    begin
+      case Buttons[i] of
+        idButtonOK       : CreateButton(tr(rsmbOK='&OK',rsmbOK, 'gtk-ok'), GTK_RESPONSE_OK);
+        idButtonCancel   : CreateButton(tr(rsmbCancel='Cancel',rsmbCancel,'gtk-cancel'), GTK_RESPONSE_CANCEL);
+        idButtonHelp     : CreateButton(tr(rsmbHelp='&Help',rsmbHelp,'gtk-help'), GTK_RESPONSE_HELP);
+        idButtonYes      : CreateButton(tr(rsmbYes='&Yes',rsmbYes,'gtk-yes'), GTK_RESPONSE_YES);
+        idButtonNo       : CreateButton(tr(rsmbNo='&No',rsmbNo,'gtk-no'), GTK_RESPONSE_NO);
+        idButtonClose    : CreateButton(tr(rsmbClose='&Close',rsmbClose,'gtk-close'), GTK_RESPONSE_CLOSE);
+        idButtonAbort    : CreateButton(rsMBAbort, GTK_RESPONSE_REJECT);
+        idButtonRetry    : CreateButton(rsMBRetry, GTK_RESPONSE_LCL_RETRY);
+        idButtonIgnore   : CreateButton(rsMBIgnore, GTK_RESPONSE_LCL_IGNORE);
+        idButtonAll      : CreateButton(rsMbAll, GTK_RESPONSE_LCL_ALL);
+        idButtonNoToAll  : CreateButton(rsMBNoToAll, GTK_RESPONSE_LCL_NOTOALL);
+        idButtonYesToAll : CreateButton(rsMBYesToAll, GTK_RESPONSE_LCL_YESTOALL);
+      end;
+    end;
+  end;
+  update_widget_list(@btn_ptr_info);
+end;
+
+
+constructor TGtk3DialogFactory.CreateMsgBox1(hWnd: HWND; lpText, lpCaption: PChar;
+  uType: Cardinal);
+var
+  ALabel : PGtkWidget;
+  ButtonCount, DefButton : Integer;
+(*  procedure CreateButton(const ALabel : PChar; const RetValue : integer);
+  var AButton : PGtkWidget;
+  begin
+    AButton:= gtk_button_new_with_label(ALabel);
+    Inc(ButtonCount);
+    if ButtonCount = DefButton then begin
+      gtk_window_set_focus(PGtkWindow(Dialog), AButton);
+    end;
+    { If there is the Cancel button, allow the dialog to close }
+    if RetValue = IDCANCEL then begin
+      g_object_set_data(PGObject(Dialog), 'modal_result', Pointer(IDCANCEL));
+    end;
+    g_object_set_data(AButton, 'modal_result',
+                        {%H-}Pointer(PtrInt(RetValue)));
+    g_signal_connect_data(AButton, 'clicked',
+                     TGCallback(@MessageButtonClicked), GPointer(@ADialogResult), nil, 0);
+    gtk_container_add (PGtkContainer(PGtkDialog(Dialog)^.get_action_area), AButton);
+  end;*)
+
+begin
+  ButtonCount:= 0;
+
+  fCaption:=lpCaption;
+  { Determine which is the default button }
+  DefButton:= ((uType and $00000300) shr 8) + 1;
+  //DebugLn('Trace:Default button is ' + IntToStr(DefButton));
+
+  DialogResult:= 0;
+  Dialog := gtk_dialog_new;
+  g_signal_connect_data(Dialog, 'delete-event', TGCallback(@BoxClosed), @DialogResult, nil, 0);
+  gtk_window_set_default_size(PGtkWindow(Dialog), 100, 100);
+  ALabel:= gtk_label_new(lpText);
+  gtk_container_add (PGtkContainer(PGtkDialog(Dialog)^.get_content_area), ALabel);
+  fDialogType:= (uType and $0000000F);
+  if fDialogType = MB_OKCANCEL
+  then begin
+    CreateButton(PChar(rsMbOK), IDOK);
+    CreateButton(PChar(rsMbCancel), IDCANCEL);
+  end
+  else begin
+    if fDialogType = MB_ABORTRETRYIGNORE
+    then begin
+      CreateButton(PChar(rsMbAbort), IDABORT);
+      CreateButton(PChar(rsMbRetry), IDRETRY);
+      CreateButton(PChar(rsMbIgnore), IDIGNORE);
+    end
+    else begin
+      if fDialogType = MB_YESNOCANCEL
+      then begin
+        CreateButton(PChar(rsMbYes), IDYES);
+        CreateButton(PChar(rsMbNo), IDNO);
+        CreateButton(PChar(rsMbCancel), IDCANCEL);
+      end
+      else begin
+        if fDialogType = MB_YESNO
+        then begin
+          CreateButton(PChar(rsMbYes), IDYES);
+          CreateButton(PChar(rsMbNo), IDNO);
+        end
+        else begin
+          if fDialogType = MB_RETRYCANCEL
+          then begin
+            CreateButton(PChar(rsMbRetry), IDRETRY);
+            CreateButton(PChar(rsMbCancel), IDCANCEL);
+          end
+          else begin
+            { We have no buttons to show. Create the default of OK button }
+            CreateButton(PChar(rsMbOK), IDOK);
+          end;
+        end;
+      end;
+    end;
+  end;
+  gtk_window_set_title(PGtkWindow(Dialog), lpCaption);
+  gtk_window_set_position(PGtkWindow(Dialog), GTK_WIN_POS_CENTER);
+  gtk_window_set_modal(PGtkWindow(Dialog), true);
+  gtk_widget_show_all(Dialog);
+end;
+
+constructor TGtk3DialogFactory.CreateMsgBox(hWnd: HWND; lpText,
+  lpCaption: PChar; uType: Cardinal);
+var
+  AType,AButtons,DefIndex:integer;
+  btns:array of integer;
+
+  procedure AddBtn(btn_res:integer);
+  begin
+    setlength(btns,length(btns)+1);
+    btns[high(btns)]:=btn_res;
+  end;
+
+begin
+  // icons
+  case uType and $000000F0 of
+//  MB_ICONEXCLAMATION:
+  MB_ICONWARNING: AType:=idDialogWarning;
+  //MB_ICONASTERISK:
+  MB_ICONINFORMATION: AType:=idDialogInfo;
+  MB_ICONQUESTION: Atype:=idDialogConfirm;
+  // MB_ICONSTOP:
+  // MB_ICONHAND:
+  MB_ICONERROR: Atype:=idDialogError;
+  end;
+  // default button
+  DefIndex:=(uType and $00000F00) shr 8;
+
+  // buttons requested
+  AButtons:= (uType and $0000000F);
+  if AButtons = MB_OKCANCEL
+  then begin
+    AddBtn(idButtonOk);
+    AddBtn(idButtonCancel);
+  end
+  else begin
+    if AButtons = MB_ABORTRETRYIGNORE
+    then begin
+      AddBtn(idButtonAbort);
+      AddBtn(idButtonRetry);
+      AddBtn(idButtonIgnore);
+    end
+    else begin
+      if AButtons = MB_YESNOCANCEL
+      then begin
+        AddBtn(idButtonYes);
+        AddBtn(idButtonNo);
+        AddBtn(idButtonCancel);
+      end
+      else begin
+        if AButtons = MB_YESNO
+        then begin
+          AddBtn(idButtonYes);
+          AddBtn(idButtonNo);
+        end
+        else begin
+          if AButtons = MB_RETRYCANCEL
+          then begin
+            AddBtn(idButtonRetry);
+            AddBtn(idButtonCancel);
+          end
+          else begin
+            { We have no buttons to show. Create the default of OK button }
+            AddBtn(idButtonOK);
+          end;
+        end;
+      end;
+    end;
+  end;
+  Self.CreatePrompt(lpCaption,lpText,AType,@btns[0],length(btns),DefIndex,0);
+end;
+
+
+end.
+
Index: lcl/interfaces/gtk3/gtk3int.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3int.pas	(revision 63603)
+++ lcl/interfaces/gtk3/gtk3int.pas	(working copy)
@@ -151,16 +151,9 @@
 
 implementation
 uses
-  Math, LCLMessageGlue,
+  Math, LCLMessageGlue, gtk3boxes,
   {%H-}Gtk3WSFactory{%H-};
 
-const
-  GTK_RESPONSE_LCL_ALL = -10;
-  GTK_RESPONSE_LCL_YESTOALL = -3; // GTK_RESPONSE_ACCEPT;
-  GTK_RESPONSE_LCL_RETRY = -12;
-  GTK_RESPONSE_LCL_IGNORE = -13;
-  GTK_RESPONSE_LCL_NOTOALL = -14;
-
 {------------------------------------------------------------------------------
   Function: FillStandardDescription
   Params:
Index: lcl/interfaces/gtk3/gtk3lclintf.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3lclintf.inc	(revision 63603)
+++ lcl/interfaces/gtk3/gtk3lclintf.inc	(working copy)
@@ -1054,337 +1054,6 @@
     Result := nil;
 end;
 
-function PromptUserBoxClosed(Widget : PGtkWidget; {%H-}Event : PGdkEvent;
-  data: gPointer) : GBoolean; cdecl;
-var
-  ModalResult : PtrUInt;
-begin
-  { We were requested by window manager to close so return EscapeResult}
-  if PInteger(data)^ = 0 then
-  begin
-    ModalResult:= {%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
-    { Don't allow to close if we don't have a default return value }
-    Result:= (ModalResult = 0);
-    if not Result then PInteger(data)^:= ModalResult
-    else DebugLn('Do not close !!!');
-  end else Result:= false;
-end;
-
-function PromptUserButtonClicked(Widget : PGtkWidget; data: gPointer) : GBoolean; cdecl;
-begin
-  PInteger(data)^ := {%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
-  Result := False;
-end;
-
-
-type
-  TBtnListfunction=function(ndx:integer):longint of object;
-  TGtk3DialogFactory = class
-    btn_def: PGtkButton;
-    DefaultNdx: Integer;
-    fButtons: TDialogButtons;
-    pButtons: PLongint;
-    fCaption: string;
-    fDialogType:longint;
-    Dialog: PGtkMessageDialog;
-    DialogResult: Integer;
-    constructor CreateAsk(const DialogCaption, DialogMessage: string;
-       DialogType: LongInt; Buttons: TDialogButtons; HelpCtx: Longint);
-    constructor CreatePrompt(const DialogCaption, DialogMessage: string;
-       DialogType: LongInt; Buttons: PLongInt;
-       ButtonCount: LongInt; DefaultIndex: LongInt; EscapeResult: LongInt);
-    class function tr(UseWidgetStr: boolean; const TranslatedStr, WidgetStr: String): string;
-    destructor Destroy;override;
-    procedure run;
-    function btn_coll_info(ndx:integer):longint;
-    function btn_ptr_info(ndx:integer):longint;
-    procedure update_widget_list(const func:TBtnListFunction);
-    procedure CreateButton(const ALabel : String; const AResponse: Integer;
-      const AImageHint: Integer = -1);
-    class function ResponseID(const AnID: Integer): Integer;
-    class function gtk_resp_to_lcl(const gtk_resp:integer):integer;
-    class function MessageType(ADialogType:longint):TGtkMessageType;
-  end;
-
-class function TGtk3DialogFactory.ResponseID(const AnID: Integer): Integer;
-begin
-  case AnID of
-    idButtonOK       : Result := GTK_RESPONSE_OK;
-    idButtonCancel   : Result := GTK_RESPONSE_CANCEL;
-    idButtonHelp     : Result := GTK_RESPONSE_HELP;
-    idButtonYes      : Result := GTK_RESPONSE_YES;
-    idButtonNo       : Result := GTK_RESPONSE_NO;
-    idButtonClose    : Result := GTK_RESPONSE_CLOSE;
-    idButtonAbort    : Result := GTK_RESPONSE_REJECT;
-    idButtonRetry    : Result := GTK_RESPONSE_LCL_RETRY;
-    idButtonIgnore   : Result := GTK_RESPONSE_LCL_IGNORE;
-    idButtonAll      : Result := GTK_RESPONSE_LCL_ALL;
-    idButtonNoToAll  : Result := GTK_RESPONSE_LCL_NOTOALL;
-    idButtonYesToAll : Result := GTK_RESPONSE_LCL_YESTOALL;
-  else
-    Result:=AnID;
-  end;
-end;
-
-
-class function TGtk3DialogFactory.gtk_resp_to_lcl(const gtk_resp:integer):integer;
-begin
-  case gtk_resp of
-  -5{GTK_RESPONSE_OK}: Result:=  mrOK;
-  -6{GTK_RESPONSE_CANCEL}:  Result := mrCancel;
-  -7{GTK_RESPONSE_CLOSE}: Result:=mrClose;
-  -8{GTK_RESPONSE_YES}: Result:=mrYes;
-  -9{GTK_RESPONSE_NO}: Result:=mrNo;
-  -10{GTK_RESPONSE_APPLY}: Result:=mrAll;
-//  -11{GTK_RESPONSE_HELP}: Result:=mrhelp;
-
-  -1{GTK_RESPONSE_NONE}: Result:=mrNone;
-  -2{GTK_RESPONSE_REJECT}: Result:=mrAbort;
-  -3{GTK_RESPONSE_ACCEPT}: Result:=mrAll;
-  else
-    Result:=gtk_resp;
-  end;
-end;
-
-procedure TGtk3DialogFactory.CreateButton(
-    const ALabel : String;
-    const AResponse: Integer;
-    const AImageHint: Integer = -1);
-var
-  NewButton: PGtkWidget;
-  //BitmapHandle, MaskHandle: HBitmap;
-  // GDIObject: PGDIObject;
-  //Pixbuf: PGdkPixbuf;
-  // Mask: PGdkBitmap;
-  //Img: PGtkWidget;
-begin
-
-  NewButton := gtk_dialog_add_button(Dialog,
-    PgChar({Ampersands2Underscore}(ALabel)), AResponse);
-  gtk_button_set_use_underline(PGtkButton(NewButton), True);
-  g_object_set_data(PGObject(NewButton), 'modal_result',
-        {%H-}Pointer(PtrInt(AResponse)));
-  (*
-  if AImageHint >= 0 then
-  begin
-    if ThemeServices.GetStockImage(AImageHint, BitmapHandle, MaskHandle) then
-    begin
-      GDIObject := {%H-}PGDIObject(BitmapHandle);
-      Mask := nil;
-      Pixbuf := nil;
-      if GDIObject^.GDIBitmapType = gbPixbuf then
-        Pixbuf := GDIObject^.GDIPixbufObject
-      else
-        Mask := CreateGdkMaskBitmap(BitmapHandle, MaskHandle);
-
-      Img := gtk_image_new;
-
-      if Pixbuf <> nil then
-        gtk_image_set_from_pixbuf(PGtkImage(Img), Pixbuf)
-      else
-        gtk_image_set_from_pixmap(PGtkImage(Img), GDIObject^.GDIPixmapObject.Image, Mask);
-      gtk_button_set_image(PGtkButton(NewButton), Img);
-      if Mask <> nil then
-        g_object_unref(Mask);
-      DeleteObject(BitmapHandle);
-      DeleteObject(MaskHandle);
-    end;
-  end;
-  *)
-end;
-
-class function TGtk3DialogFactory.MessageType(ADialogType:longint):TGtkMessageType;
-begin
-  case ADialogType of
-    idDialogWarning: Result := GTK_MESSAGE_WARNING;
-    idDialogError: Result := GTK_MESSAGE_ERROR;
-    idDialogInfo : Result := GTK_MESSAGE_INFO;
-    idDialogConfirm : Result := GTK_MESSAGE_QUESTION;
-  else
-    Result := GTK_MESSAGE_INFO;
-  end;
-end;
-
-
-const
-  ButtonResults : array[mrNone..mrYesToAll] of Longint = (
-    -1, idButtonOK, idButtonCancel, idButtonAbort, idButtonRetry,
-    idButtonIgnore, idButtonYes,idButtonNo, idButtonAll, idButtonNoToAll,
-    idButtonYesToAll);
-
-constructor TGtk3DialogFactory.CreateAsk(const DialogCaption,
-       DialogMessage: string; DialogType: LongInt;
-       Buttons: TDialogButtons; HelpCtx: Longint);
-var
-  GtkDialogType: TGtkMessageType;
-  Btns: TGtkButtonsType;
-  i, BtnIdx, BtnID: Integer;
-  dbtn:TDialogButton;
-  Title: String;
-  BtnResult: LongInt;
-begin
-  DialogResult := mrNone;
-  fDialogType := DialogType;
-  GtkDialogType := MessageType(fDialogType); // map LCLINTF -> GTK
-  fButtons:=Buttons;
-  fCaption:=DialogCaption;
-
-  Btns := GTK_BUTTONS_NONE;
-  DefaultNdx := 0;
-  for i := 0 to Buttons.Count - 1 do
-  begin
-    if Buttons[i].Default then
-      DefaultNdx := i;
-
-    if (DialogResult = mrNone) and
-      (Buttons[i].ModalResult in [mrCancel, mrAbort, mrIgnore, mrNo, mrNoToAll])
-    then
-      DialogResult := Buttons[i].ModalResult;
-  end;
-
-  Dialog := gtk_message_dialog_new(nil, GTK_DIALOG_MODAL, GtkDialogType, Btns, nil , []);
-
-  gtk_message_dialog_set_markup(PGtkMessageDialog(Dialog), PGChar(DialogMessage));
-
-  g_signal_connect_data(Dialog, 'delete-event',
-    TGCallback(@PromptUserBoxClosed),
-    @DialogResult, nil, 0);
-
-  if Btns = GTK_BUTTONS_NONE then
-  begin
-    // gtk3 have reverted buttons eg. No, Yes
-    for BtnIdx := Buttons.Count - 1 downto 0 do
-    begin
-      dbtn:=Buttons[BtnIdx];
-      if (dbtn.ModalResult >= Low(ButtonResults)) and (dbtn.ModalResult <= High(ButtonResults)) then
-      begin
-        BtnID := ButtonResults[dbtn.ModalResult];
-        case BtnID of
-          idButtonOK       : CreateButton(dbtn.Caption, GTK_RESPONSE_OK, BtnID);
-          idButtonCancel   : CreateButton(dbtn.Caption, GTK_RESPONSE_CANCEL, BtnID);
-          idButtonHelp     : CreateButton(dbtn.Caption, GTK_RESPONSE_HELP, BtnID);
-          idButtonYes      : CreateButton(dbtn.Caption, GTK_RESPONSE_YES, BtnID);
-          idButtonNo       : CreateButton(dbtn.Caption, GTK_RESPONSE_NO, BtnID);
-          idButtonClose    : CreateButton(dbtn.Caption, GTK_RESPONSE_CLOSE, BtnID);
-          idButtonAbort    : CreateButton(dbtn.Caption, GTK_RESPONSE_REJECT, BtnID);
-          idButtonRetry    : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_RETRY, BtnID);
-          idButtonIgnore   : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_IGNORE, BtnID);
-          idButtonAll      : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_ALL, BtnID);
-          idButtonNoToAll  : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_NOTOALL, BtnID);
-          idButtonYesToAll : CreateButton(dbtn.Caption, GTK_RESPONSE_LCL_YESTOALL, BtnID);
-        end;
-      end else
-         CreateButton(dbtn.Caption, dbtn.ModalResult, 0);
-
-    end;
-  end;
-
-  update_widget_list(@btn_coll_info);
-
-end;
-
-
-function TGtk3DialogFactory.btn_coll_info(ndx:integer):longint;
-begin
-  Result:=fButtons[ndx].ModalResult; // get modal result for button
-end;
-
-function TGtk3DialogFactory.btn_ptr_info(ndx:integer):longint;
-begin
-  Result:=pButtons[ndx];
-end;
-
-procedure TGtk3DialogFactory.update_widget_list(const func:TBtnListFunction);
-var
-  btn:PgtkButton;
-  BtnIdx,BtnID,BtnRes:integer;
-  MainList,ChildList: PGList;
-begin
-  MainList := gtk_container_get_children(PGtkContainer(Dialog^.get_action_area));
-  ChildList:=g_list_last(MainList);
-  BtnIdx:=0;
-  btn_def:=nil;
-  while Assigned(ChildList) do
-  begin
-    if (ChildList^.Data <> nil) then
-    begin
-      if g_type_check_instance_is_a(ChildList^.Data, gtk_button_get_type) then
-      begin
-        Btn := PGtkButton(ChildList^.Data);
-
-        BtnRes:=func(BtnIdx); // process button
-
-        if (BtnRes>=Low(ButtonResults)) and (BtnRes<=High(ButtonResults)) then
-          BtnID := ButtonResults[BtnRes]
-        else
-          BtnID := BtnRes;
-
-        if BtnID = idButtonCancel then
-           g_object_set_data(PGObject(Dialog), 'modal_result', Pointer(idButtonCancel));
-
-        g_signal_connect_data(Btn, 'clicked',
-          TGCallback(@PromptUserButtonClicked), @DialogResult, nil, 0);
-
-        if DefaultNdx = BtnIdx then
-        begin
-          gtk_dialog_set_default_response(Dialog, ResponseID(BtnID));
-          btn_def:=btn;
-          gtk_widget_grab_default(btn);
-          gtk_widget_grab_focus(btn);
-          gtk_widget_set_can_default(btn_def,TRUE);
-          gtk_window_set_default(dialog, btn_def);
-          g_object_set_data(PGObject(Dialog), 'modal_result',
-            {%H-}Pointer(PtrInt(BtnID)));
-        end;
-
-        inc(BtnIdx);
-      end;
-    end;
-    ChildList:=ChildList^.prev;
-  end;
-  if MainList <> nil then
-    g_list_free(MainList);
-
-end;
-
-procedure TGtk3DialogFactory.run;
-var
-  Title:string;
-begin
-  if not Assigned(Dialog) then exit;
-
-  if fCaption <> '' then
-    Title:=fCaption
-  else
-  begin
-    Title := '';
-    case fDialogType of
-      idDialogWarning: Title := rsMtWarning;
-      idDialogError: Title := rsMtError;
-      idDialogInfo : Title := rsMtInformation;
-      idDialogConfirm : Title := rsMtConfirmation;
-    end;
-  end;
-
-  gtk_window_set_title(PGtkWindow(Dialog), PGChar(Title));
-  gtk_dialog_run(Dialog);
-  Self.DialogResult:=Self.gtk_resp_to_lcl(Self.DialogResult);
-end;
-
-class function TGtk3DialogFactory.tr(UseWidgetStr: boolean; const TranslatedStr, WidgetStr: String): string;
-begin
-  if UseWidgetStr then
-    Result:=WidgetStr
-  else
-    Result:=TranslatedStr;
-end;
-
-destructor TGtk3DialogFactory.Destroy;
-begin
-  if Assigned(Dialog) then
-  gtk_widget_destroy(Dialog);
-end;
-
 function TGtk3WidgetSet.AskUser(const DialogCaption, DialogMessage: string; DialogType:
    LongInt; Buttons: TDialogButtons; HelpCtx: Longint): LongInt;
 var
@@ -1393,7 +1062,7 @@
   fact:=TGtk3DialogFactory.CreateAsk(DialogCaption,DialogMessage,DialogType,Buttons,HelpCtx);
   try
     fact.run;
-    Result := fact.DialogResult;
+    Result := fact.lcl_result;
   finally
     fact.Free;
   end;
@@ -1409,7 +1078,7 @@
      DialogType,Buttons,ButtonCount,DefaultIndex,EscapeResult);
   try
     fact.run;
-    Result:=fact.DialogResult;
+    Result:=fact.btn_result;
   finally
     fact.Free;
   end;
@@ -1416,60 +1085,7 @@
 
 end;
 
-constructor TGtk3DialogFactory.CreatePrompt(const DialogCaption: string;
-     const DialogMessage: string; DialogType: LongInt; Buttons: PLongInt;
-    ButtonCount: LongInt; DefaultIndex: LongInt; EscapeResult: LongInt);
-var
-  x,i:integer;
-  GtkDialogType: TGtkMessageType;
-  Btns: TGtkButtonsType;
-  DefaultID: Integer;
-begin
-  DialogResult := EscapeResult;
-  fDialogType := DialogType;
-  GtkDialogType := MessageType(fDialogType); // map LCLINTF -> GTK
-  pButtons:=Buttons;
-  fCaption:=DialogCaption;
 
-  Btns := GTK_BUTTONS_NONE;
-  DefaultId := 0;
-  for X := 0 to ButtonCount - 1 do
-  begin
-    if X = DefaultIndex then
-      DefaultID := Buttons[X];
-  end;
-
-  Dialog := gtk_message_dialog_new(nil, GTK_DIALOG_MODAL, GtkDialogType, Btns, nil , []);
-
-  gtk_message_dialog_set_markup(PGtkMessageDialog(Dialog), PGChar(DialogMessage));
-
-  g_signal_connect_data(GPointer(Dialog), 'delete-event',
-    TGCallback(@PromptUserBoxClosed),
-    @DialogResult, nil, 0);
-
-  if Btns = GTK_BUTTONS_NONE then
-  begin
-    for i := ButtonCount-1 downto 0 do
-    begin
-      case Buttons[i] of
-        idButtonOK       : CreateButton(tr(rsmbOK='&OK',rsmbOK, 'gtk-ok'), GTK_RESPONSE_OK);
-        idButtonCancel   : CreateButton(tr(rsmbCancel='Cancel',rsmbCancel,'gtk-cancel'), GTK_RESPONSE_CANCEL);
-        idButtonHelp     : CreateButton(tr(rsmbHelp='&Help',rsmbHelp,'gtk-help'), GTK_RESPONSE_HELP);
-        idButtonYes      : CreateButton(tr(rsmbYes='&Yes',rsmbYes,'gtk-yes'), GTK_RESPONSE_YES);
-        idButtonNo       : CreateButton(tr(rsmbNo='&No',rsmbNo,'gtk-no'), GTK_RESPONSE_NO);
-        idButtonClose    : CreateButton(tr(rsmbClose='&Close',rsmbClose,'gtk-close'), GTK_RESPONSE_CLOSE);
-        idButtonAbort    : CreateButton(rsMBAbort, GTK_RESPONSE_REJECT);
-        idButtonRetry    : CreateButton(rsMBRetry, GTK_RESPONSE_LCL_RETRY);
-        idButtonIgnore   : CreateButton(rsMBIgnore, GTK_RESPONSE_LCL_IGNORE);
-        idButtonAll      : CreateButton(rsMbAll, GTK_RESPONSE_LCL_ALL);
-        idButtonNoToAll  : CreateButton(rsMBNoToAll, GTK_RESPONSE_LCL_NOTOALL);
-        idButtonYesToAll : CreateButton(rsMBYesToAll, GTK_RESPONSE_LCL_YESTOALL);
-      end;
-    end;
-  end;
-  update_widget_list(@btn_ptr_info);
-end;
-
 function TGtk3WidgetSet.SetComboMinDropDownSize(Handle: HWND; MinItemsWidth,
   MinItemsHeight, MinItemCount: integer): boolean;
 var
Index: lcl/interfaces/gtk3/gtk3winapi.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 63603)
+++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
@@ -2961,116 +2961,18 @@
   Result:=true;
 end;
 
-function MessageButtonClicked(Widget : PGtkWidget; data: gPointer) : GBoolean; cdecl;
-begin
-  //DebugLn('[MessageButtonClicked] ',dbgs(data),' ',dbgs(g_object_get_data(PGtkObject(Widget), 'modal_result')));
-  if PInteger(data)^ = 0 then
-    PInteger(data)^:={%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
-  Result:=false;
-end;
-
-function MessageBoxClosed(Widget : PGtkWidget; {%H-}Event : PGdkEvent;
-  data: gPointer) : GBoolean; cdecl;
-var ModalResult : PtrUInt;
-begin
-  { We were requested by window manager to close }
-  if PInteger(data)^ = 0 then begin
-    ModalResult:= {%H-}PtrUInt(g_object_get_data(PGObject(Widget), 'modal_result'));
-    { Don't allow to close if we don't have a default return value }
-    Result:= (ModalResult = 0);
-    if not Result then PInteger(data)^:= ModalResult
-    else DebugLn('Do not close !!!');
-  end else Result:= false;
-end;
-
 function TGtk3WidgetSet.MessageBox(hWnd: HWND; lpText, lpCaption: PChar;
   uType: Cardinal): integer;
 var
-  Dialog, ALabel : PGtkWidget;
-  ButtonCount, DefButton, ADialogResult : Integer;
-  DialogType : Cardinal;
-  procedure CreateButton(const ALabel : PChar; const RetValue : integer);
-  var AButton : PGtkWidget;
-  begin
-    AButton:= gtk_button_new_with_label(ALabel);
-    Inc(ButtonCount);
-    if ButtonCount = DefButton then begin
-      gtk_window_set_focus(PGtkWindow(Dialog), AButton);
-    end;
-    { If there is the Cancel button, allow the dialog to close }
-    if RetValue = IDCANCEL then begin
-      g_object_set_data(PGObject(Dialog), 'modal_result', Pointer(IDCANCEL));
-    end;
-    g_object_set_data(AButton, 'modal_result',
-                        {%H-}Pointer(PtrInt(RetValue)));
-    g_signal_connect_data(AButton, 'clicked',
-                     TGCallback(@MessageButtonClicked), GPointer(@ADialogResult), nil, 0);
-    gtk_container_add (PGtkContainer(PGtkDialog(Dialog)^.get_action_area), AButton);
-  end;
-
+  fact:TGtk3DialogFactory;
 begin
-  ButtonCount:= 0;
-  { Determine which is the default button }
-  DefButton:= ((uType and $00000300) shr 8) + 1;
-  //DebugLn('Trace:Default button is ' + IntToStr(DefButton));
-
-  ADialogResult:= 0;
-  Dialog:= gtk_dialog_new;
-  g_signal_connect_data(Dialog, 'delete-event', TGCallback(@MessageBoxClosed), @ADialogResult, nil, 0);
-  gtk_window_set_default_size(PGtkWindow(Dialog), 100, 100);
-  ALabel:= gtk_label_new(lpText);
-  gtk_container_add (PGtkContainer(PGtkDialog(Dialog)^.get_content_area), ALabel);
-  DialogType:= (uType and $0000000F);
-  if DialogType = MB_OKCANCEL
-  then begin
-    CreateButton(PChar(rsMbOK), IDOK);
-    CreateButton(PChar(rsMbCancel), IDCANCEL);
-  end
-  else begin
-    if DialogType = MB_ABORTRETRYIGNORE
-    then begin
-      CreateButton(PChar(rsMbAbort), IDABORT);
-      CreateButton(PChar(rsMbRetry), IDRETRY);
-      CreateButton(PChar(rsMbIgnore), IDIGNORE);
-    end
-    else begin
-      if DialogType = MB_YESNOCANCEL
-      then begin
-        CreateButton(PChar(rsMbYes), IDYES);
-        CreateButton(PChar(rsMbNo), IDNO);
-        CreateButton(PChar(rsMbCancel), IDCANCEL);
-      end
-      else begin
-        if DialogType = MB_YESNO
-        then begin
-          CreateButton(PChar(rsMbYes), IDYES);
-          CreateButton(PChar(rsMbNo), IDNO);
-        end
-        else begin
-          if DialogType = MB_RETRYCANCEL
-          then begin
-            CreateButton(PChar(rsMbRetry), IDRETRY);
-            CreateButton(PChar(rsMbCancel), IDCANCEL);
-          end
-          else begin
-            { We have no buttons to show. Create the default of OK button }
-            CreateButton(PChar(rsMbOK), IDOK);
-          end;
-        end;
-      end;
-    end;
+  fact:=TGtk3DialogFactory.CreateMsgBox(hWnd,lpText,lpCaption,uType);
+  try
+    fact.run;
+    Result:=fact.lcl_result;
+  finally
+    fact.Free;
   end;
-  gtk_window_set_title(PGtkWindow(Dialog), lpCaption);
-  gtk_window_set_position(PGtkWindow(Dialog), GTK_WIN_POS_CENTER);
-  gtk_window_set_modal(PGtkWindow(Dialog), true);
-  gtk_widget_show_all(Dialog);
-  while ADialogResult = 0 do
-  begin
-    Application.HandleMessage;
-  end;
-  if Gtk3IsWidget(Dialog) then
-    gtk_widget_destroy(Dialog);
-  Result:= ADialogResult;
 end;
 
 function TGtk3WidgetSet.MonitorFromPoint(ptScreenCoords: TPoint; dwFlags: DWord
gtk3-2.diff (39,813 bytes)   

Juha Manninen

2020-07-20 16:58

developer   ~0124190

Last edited: 2020-07-20 16:59

View 2 revisions

I applied the latest patch in r63604. Thanks.
I did not test much. CudaText man and others, please test more.

I have no idea about ID_YES versus idButtonYes. Maybe forum or mailing list is a good place to ask.

Juha Manninen

2020-07-22 11:04

developer   ~0124224

Resolving.

Issue History

Date Modified Username Field Change
2020-06-26 18:06 CudaText man New Issue
2020-07-17 18:33 Anton Kavalenka Note Added: 0124128
2020-07-17 18:33 Anton Kavalenka File Added: gtk3lclintf.diff
2020-07-17 19:43 Juha Manninen Assigned To => Juha Manninen
2020-07-17 19:43 Juha Manninen Status new => assigned
2020-07-17 19:43 Juha Manninen Status assigned => resolved
2020-07-17 19:43 Juha Manninen Resolution open => fixed
2020-07-17 19:43 Juha Manninen Fixed in Revision => r63594
2020-07-17 19:43 Juha Manninen LazTarget => -
2020-07-17 19:43 Juha Manninen Widgetset GTK 3 => GTK 3
2020-07-17 19:43 Juha Manninen Note Added: 0124130
2020-07-17 23:46 CudaText man Status resolved => assigned
2020-07-17 23:46 CudaText man Resolution fixed => open
2020-07-17 23:46 CudaText man Note Added: 0124134
2020-07-18 07:47 Anton Kavalenka Note Edited: 0124128 View Revisions
2020-07-19 09:32 Anton Kavalenka Note Added: 0124167
2020-07-19 09:32 Anton Kavalenka File Added: gtk3.diff
2020-07-20 15:39 Anton Kavalenka Note Added: 0124188
2020-07-20 15:39 Anton Kavalenka File Added: gtk3-2.diff
2020-07-20 16:58 Juha Manninen Status assigned => feedback
2020-07-20 16:58 Juha Manninen Note Added: 0124190
2020-07-20 16:59 Juha Manninen Note Edited: 0124190 View Revisions
2020-07-20 17:36 Juha Manninen Fixed in Revision r63594 => r63594, r63604
2020-07-20 17:36 Juha Manninen Widgetset GTK 3 => GTK 3
2020-07-22 11:04 Juha Manninen Status feedback => resolved
2020-07-22 11:04 Juha Manninen Resolution open => fixed
2020-07-22 11:04 Juha Manninen Widgetset GTK 3 => GTK 3
2020-07-22 11:04 Juha Manninen Note Added: 0124224