1 /* QuickSynergy -- a GUI for synergy
2 * Copyright (C) 2006, 2007, 2008, 2009 Cesar L. B. Silveira, Otavio C. Cordeiro
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
17 * MA 02111-1307, USA.
18 */
19
20 #include "config.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/wait.h>
27 #include <signal.h>
28 #include <unistd.h>
29 #include <glib.h>
30 #include <gtk/gtk.h>
31 #include "callbacks.h"
32 #include "synergy_config.h"
33 #include "ui.h"
34 #include "intl.h"
35
36 #if GTK_CHECK_VERSION(2,10,0)
37 static GtkUIManager *ui_manager = NULL;
38 static GtkActionGroup *action_group;
39
40 static gchar popup_menu_actions_xml[] =
41 "<ui>\n"
42 "<popup>\n"
43 "<menuitem action=\"ActionSettings\" />\n"
44 "<separator />\n"
45 "<menuitem action=\"ActionQuit\" />\n"
46 "</popup>"
47 "</ui>\n";
48
49 static const GtkActionEntry popup_menu_actions[] = {
50 { "ActionSettings", GTK_STOCK_PREFERENCES, N_("Settings"), NULL, NULL, G_CALLBACK(show_main_window) },
51 { "ActionQuit", GTK_STOCK_QUIT, N_("Quit"), NULL, NULL, G_CALLBACK(quicksynergy_quit) },
52 };
53 #endif
54
55 extern GtkWidget *main_window;
56 extern GtkWidget *notebook;
57 extern GtkWidget *start_button;
58
entry_focus_in_event(GtkWidget * widget,GdkEventFocus * event,gpointer data)59 gboolean entry_focus_in_event(
60 GtkWidget *widget, GdkEventFocus *event, gpointer data) {
61 char *text;
62
63 text = (char *) gtk_entry_get_text(GTK_ENTRY(widget));
64
65 /* if the text on the entry is the default text (Above, Below,
66 * Left, Right), erase it when the entry gets focus */
67 if(!strcmp(text, (const char *) data))
68 gtk_entry_set_text(GTK_ENTRY(widget), "");
69
70 return FALSE;
71 }
72
entry_focus_out_event(GtkWidget * widget,GdkEventFocus * event,gpointer data)73 gboolean entry_focus_out_event(
74 GtkWidget *widget, GdkEventFocus *event, gpointer data) {
75 char *text;
76
77 text = (char *) gtk_entry_get_text(GTK_ENTRY(widget));
78
79 /* if no text was written on the entry, get back to the default text
80 * when the entry loses focus */
81 if(!strcmp(text, ""))
82 gtk_entry_set_text(GTK_ENTRY(widget), (const gchar *) data);
83
84 return FALSE;
85 }
86
entry_changed_cb(GtkEntry * entry,gpointer data)87 void entry_changed_cb(GtkEntry *entry, gpointer data) {
88 *((char **) data) = (char *) gtk_entry_get_text(entry);
89 }
90
notebook_page_switched(GtkNotebook * notebook,GtkNotebookPage * page,guint page_num,gpointer user_data)91 void notebook_page_switched(GtkNotebook *notebook, GtkNotebookPage *page,
92 guint page_num, gpointer user_data) {
93 if (page_num == 2) {
94 gtk_widget_set_sensitive(start_button, FALSE);
95 } else {
96 gtk_widget_set_sensitive(start_button, TRUE);
97 }
98 }
99
browse_button_clicked(GtkButton * button,gpointer userdata)100 void browse_button_clicked(GtkButton *button, gpointer userdata) {
101 GtkWidget *synergy_path_entry = (GtkWidget *) userdata;
102 GtkWidget *dialog;
103
104 dialog = gtk_file_chooser_dialog_new(_("Choose path to synergy binaries"),
105 GTK_WINDOW(main_window), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
106 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
107 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
108 NULL);
109
110 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
111 gchar *folder;
112
113 folder = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
114 gtk_entry_set_text(synergy_path_entry, folder);
115 g_free(folder);
116 }
117
118 gtk_widget_destroy(dialog);
119 }
120
about_button_clicked(GtkWidget * widget,gpointer data)121 void about_button_clicked(GtkWidget *widget, gpointer data) {
122 GtkWidget *window = (GtkWidget *) data;
123
124 static const gchar *authors[] = {
125 "César L. B. Silveira <cesarbs@gmail.com>",
126 "Otávio C. Cordeiro <otavio@gmail.com>",
127 "Jérémie Corbier (patches and Debian and Ubuntu packaging)",
128 "Thomas Langewouters (patches and suggestions)",
129 "Magnus Boman (patches)",
130 "Todd Wease (patches)",
131 "Avadh Patel (screen name patch)",
132 "Stephan Kleine (openSUSE packaging and patches)",
133 NULL
134 };
135
136 static const gchar *documenters[] = {
137 "César L. B. Silveira <cesarbs@gmail.com>",
138 "Otávio C. Cordeiro <otavio@gmail.com>",
139 NULL
140 };
141
142 static const gchar *copyright =
143 "Copyright \xc2\xa9 2006-2009 César L. B. Silveira, Otávio C. Cordeiro";
144
145 GdkPixbuf *logo = make_logo();
146
147 gtk_show_about_dialog(GTK_WINDOW(window),
148 "comments", _("A graphical user interface for synergy"),
149 "authors", authors,
150 "documenters", documenters,
151 "copyright", copyright,
152 "logo", logo,
153 "translator-credits", _("translator-credits"),
154 "version", VERSION,
155 "website", "http://quicksynergy.sourceforge.net",
156 "name", "QuickSynergy",
157 NULL);
158
159 if(logo) {
160 g_object_unref(logo);
161 }
162 }
163
start_button_clicked(GtkWidget * widget,gpointer data)164 void start_button_clicked(GtkWidget *widget, gpointer data) {
165 qs_state_t *state = (qs_state_t *) data;
166 const char *home_dir = getenv("HOME");
167 struct stat finfo;
168 gchar *cmd;
169 int status;
170
171 chdir(home_dir);
172
173 if(!state->running) {
174 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) == 0) {
175 save_config(state);
176 save_synergy_config(state);
177
178 cmd = g_strjoin("/", state->synergy_path, "synergys", NULL);
179
180 if (stat(cmd, &finfo) == -1) {
181 GtkWidget *dialog;
182
183 dialog = gtk_message_dialog_new(GTK_WINDOW(main_window),
184 GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
185 _("%s: File not found."), cmd);
186 gtk_window_set_title(GTK_WINDOW(dialog), _("Error"));
187
188 gtk_dialog_run(GTK_DIALOG(dialog));
189
190 gtk_widget_destroy(dialog);
191
192 g_free(cmd);
193
194 return;
195 }
196
197 state->pid = fork();
198
199 if(state->pid == 0) {
200 execlp(cmd, cmd, "-f", "--config",
201 ".quicksynergy/synergy.conf", NULL);
202 }
203
204 g_free(cmd);
205
206 gtk_widget_set_sensitive(notebook, FALSE);
207
208 state->running = SYNERGY_SERVER_RUNNING;
209 }
210 else if(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)) == 1) {
211 save_config(state);
212
213 cmd = g_strjoin("/", state->synergy_path, "synergyc", NULL);
214
215 if (stat(cmd, &finfo) == -1) {
216 GtkWidget *dialog;
217
218 dialog = gtk_message_dialog_new(GTK_WINDOW(main_window),
219 GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
220 _("%s: File not found."), cmd);
221 gtk_window_set_title(GTK_WINDOW(dialog), _("Error"));
222
223 gtk_dialog_run(GTK_DIALOG(dialog));
224
225 gtk_widget_destroy(dialog);
226
227 g_free(cmd);
228
229 return;
230 }
231
232 state->pid = fork();
233
234 if(state->pid == 0) {
235 if(!strcmp(state->client_name, "")) {
236 execlp(cmd, cmd, "-f", state->hostname, NULL);
237 } else {
238 execlp(cmd, cmd, "-f", "--name", state->client_name,
239 state->hostname, NULL);
240 }
241 }
242
243 g_free(cmd);
244
245 state->running = SYNERGY_CLIENT_RUNNING;
246 }
247
248 gtk_button_set_label(GTK_BUTTON(widget), GTK_STOCK_MEDIA_STOP);
249 gtk_widget_set_sensitive(notebook, FALSE);
250 }
251 else {
252 kill(state->pid, SIGTERM);
253
254 wait(&status);
255
256 gtk_button_set_label(GTK_BUTTON(widget), GTK_STOCK_EXECUTE);
257 gtk_widget_set_sensitive(notebook, TRUE);
258
259 state->running = 0;
260 }
261 }
262
263 #if GTK_CHECK_VERSION(2,10,0)
quicksynergy_quit(GtkWidget * widget,gpointer data)264 void quicksynergy_quit(GtkWidget *widget, gpointer data) {
265 qs_state_t *state = (qs_state_t *) data;
266
267 if(state->running) {
268 kill(state->pid, SIGTERM);
269 }
270
271 save_config(state);
272
273 gtk_main_quit();
274 }
275
close_button_clicked(GtkWidget * widget,gpointer data)276 void close_button_clicked(GtkWidget *widget, gpointer data) {
277 gtk_widget_hide_all(main_window);
278 }
279
delete_event(GtkWidget * widget,GdkEvent * event,gpointer data)280 gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) {
281 gtk_widget_hide_all(widget);
282
283 return TRUE;
284 }
285 #else
close_button_clicked(GtkWidget * widget,gpointer data)286 void close_button_clicked(GtkWidget *widget, gpointer data) {
287 qs_state_t *state = (qs_state_t *) data;
288
289 if(state->running) {
290 kill(state->pid, SIGTERM);
291 }
292
293 save_config(state);
294
295 gtk_main_quit();
296 }
297
delete_event(GtkWidget * widget,GdkEvent * event,gpointer data)298 gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) {
299 qs_state_t *state = (qs_state_t *) data;
300
301 if(state->running) {
302 kill(state->pid, SIGTERM);
303 }
304
305 save_config(state);
306
307 return FALSE;
308 }
309 #endif
310
311 #if GTK_CHECK_VERSION(2,10,0)
show_main_window(GtkWidget * widget,gpointer data)312 void show_main_window(GtkWidget *widget, gpointer data) {
313 qs_state_t *state = (qs_state_t *) data;
314
315 gtk_widget_show_all(main_window);
316
317 if(!state->running || state->running == SYNERGY_SERVER_RUNNING) {
318 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
319 }
320 else {
321 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 1);
322 }
323 }
324
status_icon_popup(GtkStatusIcon * status_icon,guint button,guint activate_time,gpointer data)325 void status_icon_popup(GtkStatusIcon *status_icon, guint button,
326 guint activate_time, gpointer data) {
327 GtkWidget *popup_menu;
328
329 if(!ui_manager) {
330 ui_manager = gtk_ui_manager_new();
331 action_group = gtk_action_group_new("QSpopup");
332
333 #ifdef ENABLE_NLS
334 gtk_action_group_set_translation_domain(action_group, PACKAGE);
335 #endif
336 gtk_action_group_add_actions(action_group, popup_menu_actions, 2, data);
337
338 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
339 gtk_ui_manager_add_ui_from_string(ui_manager, popup_menu_actions_xml,
340 -1, NULL);
341 }
342
343 popup_menu = gtk_ui_manager_get_widget(ui_manager, "/popup");
344
345 gtk_widget_show_all(popup_menu);
346
347 gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL,
348 gtk_status_icon_position_menu, status_icon, button, activate_time);
349 }
350 #endif
351
352