| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/disconnect_window.h" | |
| 6 | |
| 7 #include <gtk/gtk.h> | 5 #include <gtk/gtk.h> |
| 8 #include <math.h> | 6 #include <math.h> |
| 9 | 7 |
| 10 #include "base/compiler_specific.h" | 8 #include "base/compiler_specific.h" |
| 11 #include "base/logging.h" | 9 #include "base/logging.h" |
| 12 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 13 #include "base/utf_string_conversions.h" | 11 #include "base/utf_string_conversions.h" |
| 12 #include "remoting/host/client_session_control.h" |
| 13 #include "remoting/host/host_window.h" |
| 14 #include "remoting/host/ui_strings.h" | 14 #include "remoting/host/ui_strings.h" |
| 15 #include "ui/base/gtk/gtk_signal.h" | 15 #include "ui/base/gtk/gtk_signal.h" |
| 16 | 16 |
| 17 namespace remoting { | 17 namespace remoting { |
| 18 | 18 |
| 19 class DisconnectWindowGtk : public DisconnectWindow { | 19 namespace { |
| 20 |
| 21 class DisconnectWindowGtk : public HostWindow { |
| 20 public: | 22 public: |
| 21 explicit DisconnectWindowGtk(const UiStrings* ui_strings); | 23 explicit DisconnectWindowGtk(const UiStrings& ui_strings); |
| 22 virtual ~DisconnectWindowGtk(); | 24 virtual ~DisconnectWindowGtk(); |
| 23 | 25 |
| 24 virtual bool Show(const base::Closure& disconnect_callback, | 26 // HostWindow overrides. |
| 25 const std::string& username) OVERRIDE; | 27 virtual void Start( |
| 26 virtual void Hide() OVERRIDE; | 28 const base::WeakPtr<ClientSessionControl>& client_session_control) |
| 29 OVERRIDE; |
| 27 | 30 |
| 28 private: | 31 private: |
| 29 CHROMEGTK_CALLBACK_1(DisconnectWindowGtk, gboolean, OnDelete, GdkEvent*); | 32 CHROMEGTK_CALLBACK_1(DisconnectWindowGtk, gboolean, OnDelete, GdkEvent*); |
| 30 CHROMEGTK_CALLBACK_0(DisconnectWindowGtk, void, OnClicked); | 33 CHROMEGTK_CALLBACK_0(DisconnectWindowGtk, void, OnClicked); |
| 31 CHROMEGTK_CALLBACK_1(DisconnectWindowGtk, gboolean, OnConfigure, | 34 CHROMEGTK_CALLBACK_1(DisconnectWindowGtk, gboolean, OnConfigure, |
| 32 GdkEventConfigure*); | 35 GdkEventConfigure*); |
| 33 CHROMEGTK_CALLBACK_1(DisconnectWindowGtk, gboolean, OnButtonPress, | 36 CHROMEGTK_CALLBACK_1(DisconnectWindowGtk, gboolean, OnButtonPress, |
| 34 GdkEventButton*); | 37 GdkEventButton*); |
| 35 | 38 |
| 36 void CreateWindow(); | 39 // Used to disconnect the client session. |
| 40 base::WeakPtr<ClientSessionControl> client_session_control_; |
| 37 | 41 |
| 38 base::Closure disconnect_callback_; | 42 // Localized UI strings. |
| 43 UiStrings ui_strings_; |
| 44 |
| 39 GtkWidget* disconnect_window_; | 45 GtkWidget* disconnect_window_; |
| 40 GtkWidget* message_; | 46 GtkWidget* message_; |
| 41 GtkWidget* button_; | 47 GtkWidget* button_; |
| 42 | 48 |
| 43 // Used to distinguish resize events from other types of "configure-event" | 49 // Used to distinguish resize events from other types of "configure-event" |
| 44 // notifications. | 50 // notifications. |
| 45 int current_width_; | 51 int current_width_; |
| 46 int current_height_; | 52 int current_height_; |
| 47 | 53 |
| 48 // Points to the localized strings. | |
| 49 const UiStrings* ui_strings_; | |
| 50 | |
| 51 DISALLOW_COPY_AND_ASSIGN(DisconnectWindowGtk); | 54 DISALLOW_COPY_AND_ASSIGN(DisconnectWindowGtk); |
| 52 }; | 55 }; |
| 53 | 56 |
| 54 DisconnectWindowGtk::DisconnectWindowGtk(const UiStrings* ui_strings) | 57 // Helper function for creating a rectangular path with rounded corners, as |
| 55 : disconnect_window_(NULL), | 58 // Cairo doesn't have this facility. |radius| is the arc-radius of each |
| 59 // corner. The bounding rectangle extends from (0, 0) to (width, height). |
| 60 void AddRoundRectPath(cairo_t* cairo_context, int width, int height, |
| 61 int radius) { |
| 62 cairo_new_sub_path(cairo_context); |
| 63 cairo_arc(cairo_context, width - radius, radius, radius, -M_PI_2, 0); |
| 64 cairo_arc(cairo_context, width - radius, height - radius, radius, 0, M_PI_2); |
| 65 cairo_arc(cairo_context, radius, height - radius, radius, M_PI_2, 2 * M_PI_2); |
| 66 cairo_arc(cairo_context, radius, radius, radius, 2 * M_PI_2, 3 * M_PI_2); |
| 67 cairo_close_path(cairo_context); |
| 68 } |
| 69 |
| 70 DisconnectWindowGtk::DisconnectWindowGtk(const UiStrings& ui_strings) |
| 71 : ui_strings_(ui_strings), |
| 72 disconnect_window_(NULL), |
| 56 current_width_(0), | 73 current_width_(0), |
| 57 current_height_(0), | 74 current_height_(0) { |
| 58 ui_strings_(ui_strings) { | |
| 59 } | 75 } |
| 60 | 76 |
| 61 DisconnectWindowGtk::~DisconnectWindowGtk() { | 77 DisconnectWindowGtk::~DisconnectWindowGtk() { |
| 62 Hide(); | 78 DCHECK(CalledOnValidThread()); |
| 79 |
| 80 if (disconnect_window_) { |
| 81 gtk_widget_destroy(disconnect_window_); |
| 82 disconnect_window_ = NULL; |
| 83 } |
| 63 } | 84 } |
| 64 | 85 |
| 65 void DisconnectWindowGtk::CreateWindow() { | 86 void DisconnectWindowGtk::Start( |
| 66 if (disconnect_window_) | 87 const base::WeakPtr<ClientSessionControl>& client_session_control) { |
| 67 return; | 88 DCHECK(CalledOnValidThread()); |
| 89 DCHECK(!client_session_control_); |
| 90 DCHECK(client_session_control); |
| 91 DCHECK(!disconnect_window_); |
| 68 | 92 |
| 93 client_session_control_ = client_session_control; |
| 94 |
| 95 // Create the window. |
| 69 disconnect_window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); | 96 disconnect_window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
| 70 GtkWindow* window = GTK_WINDOW(disconnect_window_); | 97 GtkWindow* window = GTK_WINDOW(disconnect_window_); |
| 71 | 98 |
| 72 g_signal_connect(disconnect_window_, "delete-event", | 99 g_signal_connect(disconnect_window_, "delete-event", |
| 73 G_CALLBACK(OnDeleteThunk), this); | 100 G_CALLBACK(OnDeleteThunk), this); |
| 74 gtk_window_set_title(window, UTF16ToUTF8(ui_strings_->product_name).c_str()); | 101 gtk_window_set_title(window, UTF16ToUTF8(ui_strings_.product_name).c_str()); |
| 75 gtk_window_set_resizable(window, FALSE); | 102 gtk_window_set_resizable(window, FALSE); |
| 76 | 103 |
| 77 // Try to keep the window always visible. | 104 // Try to keep the window always visible. |
| 78 gtk_window_stick(window); | 105 gtk_window_stick(window); |
| 79 gtk_window_set_keep_above(window, TRUE); | 106 gtk_window_set_keep_above(window, TRUE); |
| 80 | 107 |
| 81 // Remove window titlebar. | 108 // Remove window titlebar. |
| 82 gtk_window_set_decorated(window, FALSE); | 109 gtk_window_set_decorated(window, FALSE); |
| 83 | 110 |
| 84 // In case the titlebar is still there, try to remove some of the buttons. | 111 // In case the titlebar is still there, try to remove some of the buttons. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 108 // left and right. The left margin is made larger to accommodate the | 135 // left and right. The left margin is made larger to accommodate the |
| 109 // window movement gripper. | 136 // window movement gripper. |
| 110 GtkWidget* align = gtk_alignment_new(0, 0, 1, 1); | 137 GtkWidget* align = gtk_alignment_new(0, 0, 1, 1); |
| 111 gtk_alignment_set_padding(GTK_ALIGNMENT(align), 8, 8, 24, 12); | 138 gtk_alignment_set_padding(GTK_ALIGNMENT(align), 8, 8, 24, 12); |
| 112 gtk_container_add(GTK_CONTAINER(window), align); | 139 gtk_container_add(GTK_CONTAINER(window), align); |
| 113 | 140 |
| 114 GtkWidget* button_row = gtk_hbox_new(FALSE, 12); | 141 GtkWidget* button_row = gtk_hbox_new(FALSE, 12); |
| 115 gtk_container_add(GTK_CONTAINER(align), button_row); | 142 gtk_container_add(GTK_CONTAINER(align), button_row); |
| 116 | 143 |
| 117 button_ = gtk_button_new_with_label( | 144 button_ = gtk_button_new_with_label( |
| 118 UTF16ToUTF8(ui_strings_->disconnect_button_text).c_str()); | 145 UTF16ToUTF8(ui_strings_.disconnect_button_text).c_str()); |
| 119 gtk_box_pack_end(GTK_BOX(button_row), button_, FALSE, FALSE, 0); | 146 gtk_box_pack_end(GTK_BOX(button_row), button_, FALSE, FALSE, 0); |
| 120 | 147 |
| 121 g_signal_connect(button_, "clicked", G_CALLBACK(OnClickedThunk), this); | 148 g_signal_connect(button_, "clicked", G_CALLBACK(OnClickedThunk), this); |
| 122 | 149 |
| 123 message_ = gtk_label_new(NULL); | 150 message_ = gtk_label_new(NULL); |
| 124 gtk_box_pack_end(GTK_BOX(button_row), message_, FALSE, FALSE, 0); | 151 gtk_box_pack_end(GTK_BOX(button_row), message_, FALSE, FALSE, 0); |
| 125 | 152 |
| 126 // Override any theme setting for the text color, so that the text is | 153 // Override any theme setting for the text color, so that the text is |
| 127 // readable against the window's background pixmap. | 154 // readable against the window's background pixmap. |
| 128 PangoAttrList* attributes = pango_attr_list_new(); | 155 PangoAttrList* attributes = pango_attr_list_new(); |
| 129 PangoAttribute* text_color = pango_attr_foreground_new(0, 0, 0); | 156 PangoAttribute* text_color = pango_attr_foreground_new(0, 0, 0); |
| 130 pango_attr_list_insert(attributes, text_color); | 157 pango_attr_list_insert(attributes, text_color); |
| 131 gtk_label_set_attributes(GTK_LABEL(message_), attributes); | 158 gtk_label_set_attributes(GTK_LABEL(message_), attributes); |
| 132 | 159 |
| 133 gtk_widget_show_all(disconnect_window_); | 160 gtk_widget_show_all(disconnect_window_); |
| 134 } | |
| 135 | 161 |
| 136 bool DisconnectWindowGtk::Show(const base::Closure& disconnect_callback, | 162 // Extract the user name from the JID. |
| 137 const std::string& username) { | 163 std::string client_jid = client_session_control_->client_jid(); |
| 138 DCHECK(disconnect_callback_.is_null()); | 164 string16 username = UTF8ToUTF16(client_jid.substr(0, client_jid.find('/'))); |
| 139 DCHECK(!disconnect_callback.is_null()); | 165 string16 text = |
| 140 DCHECK(!disconnect_window_); | 166 ReplaceStringPlaceholders(ui_strings_.disconnect_message, username, NULL); |
| 141 | |
| 142 disconnect_callback_ = disconnect_callback; | |
| 143 CreateWindow(); | |
| 144 | |
| 145 string16 text = ReplaceStringPlaceholders( | |
| 146 ui_strings_->disconnect_message, UTF8ToUTF16(username), NULL); | |
| 147 gtk_label_set_text(GTK_LABEL(message_), UTF16ToUTF8(text).c_str()); | 167 gtk_label_set_text(GTK_LABEL(message_), UTF16ToUTF8(text).c_str()); |
| 148 gtk_window_present(GTK_WINDOW(disconnect_window_)); | 168 gtk_window_present(window); |
| 149 return true; | |
| 150 } | |
| 151 | |
| 152 void DisconnectWindowGtk::Hide() { | |
| 153 if (disconnect_window_) { | |
| 154 gtk_widget_destroy(disconnect_window_); | |
| 155 disconnect_window_ = NULL; | |
| 156 } | |
| 157 | |
| 158 disconnect_callback_.Reset(); | |
| 159 } | 169 } |
| 160 | 170 |
| 161 void DisconnectWindowGtk::OnClicked(GtkWidget* button) { | 171 void DisconnectWindowGtk::OnClicked(GtkWidget* button) { |
| 162 disconnect_callback_.Run(); | 172 DCHECK(CalledOnValidThread()); |
| 163 Hide(); | 173 |
| 174 if (client_session_control_) { |
| 175 client_session_control_->DisconnectSession(); |
| 176 client_session_control_.reset(); |
| 177 } |
| 164 } | 178 } |
| 165 | 179 |
| 166 gboolean DisconnectWindowGtk::OnDelete(GtkWidget* window, GdkEvent* event) { | 180 gboolean DisconnectWindowGtk::OnDelete(GtkWidget* window, |
| 167 disconnect_callback_.Run(); | 181 GdkEvent* event) { |
| 168 Hide(); | 182 DCHECK(CalledOnValidThread()); |
| 169 | 183 |
| 184 if (client_session_control_) { |
| 185 client_session_control_->DisconnectSession(); |
| 186 client_session_control_.reset(); |
| 187 } |
| 170 return TRUE; | 188 return TRUE; |
| 171 } | 189 } |
| 172 | 190 |
| 173 namespace { | 191 gboolean DisconnectWindowGtk::OnConfigure(GtkWidget* widget, |
| 174 // Helper function for creating a rectangular path with rounded corners, as | 192 GdkEventConfigure* event) { |
| 175 // Cairo doesn't have this facility. |radius| is the arc-radius of each | 193 DCHECK(CalledOnValidThread()); |
| 176 // corner. The bounding rectangle extends from (0, 0) to (width, height). | |
| 177 void AddRoundRectPath(cairo_t* cairo_context, int width, int height, | |
| 178 int radius) { | |
| 179 cairo_new_sub_path(cairo_context); | |
| 180 cairo_arc(cairo_context, width - radius, radius, radius, -M_PI_2, 0); | |
| 181 cairo_arc(cairo_context, width - radius, height - radius, radius, 0, M_PI_2); | |
| 182 cairo_arc(cairo_context, radius, height - radius, radius, M_PI_2, 2 * M_PI_2); | |
| 183 cairo_arc(cairo_context, radius, radius, radius, 2 * M_PI_2, 3 * M_PI_2); | |
| 184 cairo_close_path(cairo_context); | |
| 185 } | |
| 186 | 194 |
| 187 } // namespace | |
| 188 | |
| 189 gboolean DisconnectWindowGtk::OnConfigure(GtkWidget* widget, | |
| 190 GdkEventConfigure* event) { | |
| 191 // Only generate bitmaps if the size has actually changed. | 195 // Only generate bitmaps if the size has actually changed. |
| 192 if (event->width == current_width_ && event->height == current_height_) | 196 if (event->width == current_width_ && event->height == current_height_) |
| 193 return FALSE; | 197 return FALSE; |
| 194 | 198 |
| 195 current_width_ = event->width; | 199 current_width_ = event->width; |
| 196 current_height_ = event->height; | 200 current_height_ = event->height; |
| 197 | 201 |
| 198 // Create the depth 1 pixmap for the window shape. | 202 // Create the depth 1 pixmap for the window shape. |
| 199 GdkPixmap* shape_mask = gdk_pixmap_new(NULL, current_width_, current_height_, | 203 GdkPixmap* shape_mask = gdk_pixmap_new(NULL, current_width_, current_height_, |
| 200 1); | 204 1); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 cairo_destroy(cairo_context); | 270 cairo_destroy(cairo_context); |
| 267 | 271 |
| 268 gdk_window_set_back_pixmap(widget->window, background, FALSE); | 272 gdk_window_set_back_pixmap(widget->window, background, FALSE); |
| 269 g_object_unref(background); | 273 g_object_unref(background); |
| 270 gdk_window_invalidate_rect(widget->window, NULL, TRUE); | 274 gdk_window_invalidate_rect(widget->window, NULL, TRUE); |
| 271 | 275 |
| 272 return FALSE; | 276 return FALSE; |
| 273 } | 277 } |
| 274 | 278 |
| 275 gboolean DisconnectWindowGtk::OnButtonPress(GtkWidget* widget, | 279 gboolean DisconnectWindowGtk::OnButtonPress(GtkWidget* widget, |
| 276 GdkEventButton* event) { | 280 GdkEventButton* event) { |
| 281 DCHECK(CalledOnValidThread()); |
| 282 |
| 277 gtk_window_begin_move_drag(GTK_WINDOW(disconnect_window_), | 283 gtk_window_begin_move_drag(GTK_WINDOW(disconnect_window_), |
| 278 event->button, | 284 event->button, |
| 279 event->x_root, | 285 event->x_root, |
| 280 event->y_root, | 286 event->y_root, |
| 281 event->time); | 287 event->time); |
| 282 return FALSE; | 288 return FALSE; |
| 283 } | 289 } |
| 284 | 290 |
| 285 scoped_ptr<DisconnectWindow> DisconnectWindow::Create( | 291 } // namespace |
| 286 const UiStrings* ui_strings) { | 292 |
| 287 return scoped_ptr<DisconnectWindow>(new DisconnectWindowGtk(ui_strings)); | 293 // static |
| 294 scoped_ptr<HostWindow> HostWindow::CreateDisconnectWindow( |
| 295 const UiStrings& ui_strings) { |
| 296 return scoped_ptr<HostWindow>(new DisconnectWindowGtk(ui_strings)); |
| 288 } | 297 } |
| 289 | 298 |
| 290 } // namespace remoting | 299 } // namespace remoting |
| OLD | NEW |