--- file_not_specified_in_diff +++ file_not_specified_in_diff @@ -, +, @@ --- brackets-shell/appshell/cefclient_gtk.cpp +++ brackets-shell/appshell/cefclient_gtk.cpp @@ -1,6 +1,8 @@ // Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. + +#include #include "cefclient.h" #include @@ -18,47 +20,78 @@ #include "client_switches.h" #include "appshell_node_process.h" -static std::string APPICONS[] = {"appshell32.png","appshell48.png","appshell128.png","appshell256.png"}; -char szWorkingDir[512]; // The current working directory +static std::string APPICONS[] = {"appshell32.png", "appshell48.png", "appshell128.png", "appshell256.png"}; +char szWorkingDir[512]; // The current working directory std::string szInitialUrl; std::string szRunningDir; int add_handler_id; bool isReallyClosing = false; +static gint DEFAULT_SIZE_HEIGHT = 600; +static gint DEFAULT_SIZE_WIDTH = 800; + // The global ClientHandler reference. extern CefRefPtr g_handler; // Application startup time time_t g_appStartupTime; +// Error handler for X11 + +int XErrorHandlerImpl(Display *display, XErrorEvent *event) { + LOG(WARNING) + << "X error received: " + << "type " << event->type << ", " + << "serial " << event->serial << ", " + << "error_code " << static_cast (event->error_code) << ", " + << "request_code " << static_cast (event->request_code) << ", " + << "minor_code " << static_cast (event->minor_code); + return 0; +} + +int XIOErrorHandlerImpl(Display *display) { + return 0; +} + void destroy(void) { - CefQuitMessageLoop(); -} - -void TerminationSignalHandler(int signatl) { + if (isReallyClosing) { + CefQuitMessageLoop(); + } +} + +void TerminationSignalHandler(int signal) { + isReallyClosing = true; destroy(); } -void HandleAdd(GtkContainer *container, - GtkWidget *widget, - gpointer user_data) { - g_signal_handler_disconnect(container, add_handler_id); - if(gtk_widget_get_can_focus(widget)) { - gtk_widget_grab_focus(widget); - } - else { - add_handler_id = g_signal_connect(G_OBJECT(widget), "add", - G_CALLBACK(HandleAdd), NULL); - } -} - -static gboolean HandleQuit(int signatl) { - if (!isReallyClosing && g_handler.get() && g_handler->GetBrowserId()) { - CefRefPtr callback = new CloseWindowCommandCallback(g_handler->GetBrowser()); + +//void HandleAdd(GtkContainer *container, +// GtkWidget *widget, +// gpointer user_data) { +// g_signal_handler_disconnect(container, add_handler_id); +// if (gtk_widget_get_can_focus(widget)) { +// gtk_widget_grab_focus(widget); +// } else { +// add_handler_id = g_signal_connect(G_OBJECT(widget), "add", +// G_CALLBACK(HandleAdd), NULL); +// } +//} + +// TODO: this is not yet called to shutdown Brackets +gboolean HandleQuit() { + + if (!isReallyClosing && g_handler.get()) { + g_handler->DispatchCloseToNextBrowser(); + } + else + { + if(!g_handler.get() || !g_handler->HasWindows()) { + CefQuitMessageLoop(); + return FALSE; + } + } + + return TRUE; - g_handler->SendJSCommand(g_handler->GetBrowser(), FILE_CLOSE_WINDOW, callback); - return TRUE; - } - destroy(); } bool FileExists(std::string path) { @@ -68,22 +101,21 @@ int GetInitialUrl() { GtkWidget *dialog; - const char* dialog_title = "Please select the index.html file"; - GtkFileChooserAction file_or_directory = GTK_FILE_CHOOSER_ACTION_OPEN ; - dialog = gtk_file_chooser_dialog_new (dialog_title, - NULL, - file_or_directory, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - NULL); - - if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) - { - szInitialUrl = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); - gtk_widget_destroy (dialog); - return 0; - } - return -1; + const char* dialog_title = "Please select the index.html file"; + GtkFileChooserAction file_or_directory = GTK_FILE_CHOOSER_ACTION_OPEN; + dialog = gtk_file_chooser_dialog_new(dialog_title, + NULL, + file_or_directory, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + szInitialUrl = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + gtk_widget_destroy(dialog); + return 0; + } + return -1; } // Global functions @@ -93,17 +125,17 @@ } std::string AppGetRunningDirectory() { - if(szRunningDir.length() > 0) + if (szRunningDir.length() > 0) return szRunningDir; char buf[512]; int len = readlink("/proc/self/exe", buf, 512); - if(len < 0) - return AppGetWorkingDirectory(); //# Well, can't think of any real-world case where this would be happen - - for(; len >= 0; len--){ - if(buf[len] == '/'){ + if (len < 0) + return AppGetWorkingDirectory(); //# Well, can't think of any real-world case where this would be happen + + for (; len >= 0; len--) { + if (buf[len] == '/') { buf[len] = '\0'; szRunningDir.append(buf); return szRunningDir; @@ -118,7 +150,7 @@ } GtkWidget* AddMenuEntry(GtkWidget* menu_widget, const char* text, - GCallback callback) { + GCallback callback) { GtkWidget* entry = gtk_menu_item_new_with_label(text); g_signal_connect(entry, "activate", callback, NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu_widget), entry); @@ -138,6 +170,65 @@ return FALSE; } +gboolean WindowConfigure(GtkWindow* window, + GdkEvent* event, + gpointer data) { + // Called when size, position or stack order changes. + if (g_handler) { + CefRefPtr browser = g_handler->GetBrowser(); + if (browser) { + // Notify the browser of move/resize events so that: + // - Popup windows are displayed in the correct location and dismissed + // when the window moves. + // - Drag&drop areas are updated accordingly. + browser->GetHost()->NotifyMoveOrResizeStarted(); + } + } + + return FALSE; // Don't stop this message. +} + +void VboxSizeAllocated(GtkWidget* widget, + GtkAllocation* allocation, + void* data) { + if (g_handler) { + CefRefPtr browser = g_handler->GetBrowser(); + if (browser && !browser->GetHost()->IsWindowRenderingDisabled()) { + // Size the browser window to match the GTK widget. + ::Display* xdisplay = cef_get_xdisplay(); + ::Window xwindow = browser->GetHost()->GetWindowHandle(); + XWindowChanges changes = {0}; + + // TODO: get the real value + int g_menubar_height = 0; + changes.width = allocation->width; + changes.height = allocation->height - (g_menubar_height); + changes.y = g_menubar_height; + XConfigureWindow(xdisplay, xwindow, CWHeight | CWWidth | CWY, &changes); + } + } +} + +gboolean WindowFocusIn(GtkWidget* widget, + GdkEventFocus* event, + gpointer user_data) { + if (g_handler && event->in) { + CefRefPtr browser = g_handler->GetBrowser(); + if (browser) { + if (browser->GetHost()->IsWindowRenderingDisabled()) { + // Give focus to the off-screen browser. + browser->GetHost()->SendFocusEvent(true); + } else { + // Give focus to the browser window. + browser->GetHost()->SetFocus(true); + return TRUE; + } + } + } + + return FALSE; +} + int main(int argc, char* argv[]) { CefMainArgs main_args(argc, argv); @@ -155,10 +246,13 @@ if (!getcwd(szWorkingDir, sizeof (szWorkingDir))) return -1; - GtkWidget* window; - // Parse command line arguments. AppInitCommandLine(argc, argv); + + // Install xlib error handlers so that the application won't be terminated + // on non-fatal errors. + XSetErrorHandler(XErrorHandlerImpl); + XSetIOErrorHandler(XIOErrorHandlerImpl); CefSettings settings; @@ -171,19 +265,19 @@ if (CefString(&settings.cache_path).length() == 0) { CefString(&settings.cache_path) = AppGetCachePath(); } - + CefRefPtr cmdLine = AppGetCommandLine(); - + if (cmdLine->HasSwitch(cefclient::kStartupPath)) { szInitialUrl = cmdLine->GetSwitchValue(cefclient::kStartupPath); } else { szInitialUrl = AppGetRunningDirectory(); szInitialUrl.append("/dev/src/index.html"); - + if (!FileExists(szInitialUrl)) { szInitialUrl = AppGetRunningDirectory(); szInitialUrl.append("/www/index.html"); - + if (!FileExists(szInitialUrl)) { if (GetInitialUrl() < 0) return 0; @@ -191,32 +285,38 @@ } } + // Start the node server process + startNodeProcess(); + // Initialize CEF. CefInitialize(main_args, settings, app.get(), NULL); - + // Set window icon - std::vector icons(APPICONS, APPICONS + sizeof(APPICONS) / sizeof(APPICONS[0]) ); + std::vector icons(APPICONS, APPICONS + sizeof (APPICONS) / sizeof (APPICONS[0])); GList *list = NULL; for (int i = 0; i < icons.size(); ++i) { std::string path = icons[i]; - + GdkPixbuf *icon = gdk_pixbuf_new_from_file(path.c_str(), NULL); if (!icon) - continue; - + continue; + list = g_list_append(list, icon); } - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); + GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(window), DEFAULT_SIZE_WIDTH, DEFAULT_SIZE_HEIGHT); gtk_window_set_icon_list(GTK_WINDOW(window), list); - + // Free icon list g_list_foreach(list, (GFunc) g_object_unref, NULL); g_list_free(list); GtkWidget* vbox = gtk_vbox_new(FALSE, 0); + g_signal_connect(vbox, "size-allocate", + G_CALLBACK(VboxSizeAllocated), NULL); + gtk_container_add(GTK_CONTAINER(window), vbox); GtkWidget* menuBar = gtk_menu_bar_new(); // GtkWidget* debug_menu = CreateMenu(menuBar, "Tests"); @@ -225,18 +325,23 @@ gtk_box_pack_start(GTK_BOX(vbox), menuBar, FALSE, FALSE, 0); + // setup all event listener to handle focus, resizing, destruction + g_signal_connect(G_OBJECT(window), "configure-event", + G_CALLBACK(WindowConfigure), NULL); + g_signal_connect(G_OBJECT(window), "focus-in-event", + G_CALLBACK(WindowFocusIn), NULL); g_signal_connect(G_OBJECT(window), "delete_event", - G_CALLBACK(HandleQuit), NULL); + G_CALLBACK(HandleQuit), NULL); g_signal_connect(G_OBJECT(window), "destroy", - G_CALLBACK(gtk_widget_destroyed), &window); - add_handler_id = g_signal_connect(G_OBJECT(window), "add", - G_CALLBACK(HandleAdd), NULL); - // g_signal_connect(G_OBJECT(window), "destroy", - // G_CALLBACK(destroy), NULL); + G_CALLBACK(destroy), window); + +// add_handler_id = g_signal_connect(G_OBJECT(window), "add", +// G_CALLBACK(HandleAdd), NULL); // Create the handler. g_handler = new ClientHandler(); g_handler->SetMainHwnd(vbox); +// g_handler->SetMainHwnd(window); // Create the browser view. CefWindowInfo window_info; @@ -244,22 +349,21 @@ browserSettings.web_security = STATE_DISABLED; - window_info.SetAsChild(vbox); - + // show the window + gtk_widget_show_all(GTK_WIDGET(window)); + + window_info.SetAsChild(GDK_WINDOW_XID(gtk_widget_get_window(window)), + CefRect(0, 0, DEFAULT_SIZE_WIDTH, DEFAULT_SIZE_HEIGHT)); + + // Create the browser window CefBrowserHost::CreateBrowser( - window_info, - static_cast >(g_handler), - "file://"+szInitialUrl, browserSettings, NULL); - - gtk_container_add(GTK_CONTAINER(window), vbox); - gtk_widget_show_all(GTK_WIDGET(window)); + window_info, + g_handler.get(), + "file://" + szInitialUrl, browserSettings, NULL); // Install an signal handler so we clean up after ourselves. signal(SIGINT, TerminationSignalHandler); signal(SIGTERM, TerminationSignalHandler); - - // Start the node server process - startNodeProcess(); CefRunMessageLoop(); @@ -277,3 +381,4 @@ // TODO return CefString(""); } +