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