12 #include <sys/types.h>
15 #include <YCommandLine.h>
22 static std::string askForFileOrDirectory (GtkFileChooserAction action,
23 const std::string &path,
const std::string &filter,
const std::string &title);
25 static void errorMsg (
const char *msg)
27 GtkWidget* dialog = gtk_message_dialog_new (NULL,
28 GtkDialogFlags (0), GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
"%s", _(
"Error"));
29 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", msg);
30 gtk_dialog_run (GTK_DIALOG (dialog));
31 gtk_widget_destroy (dialog);
34 #define DEFAULT_MACRO_FILE_NAME "macro.ycp"
35 #define BUSY_CURSOR_TIMEOUT 250
37 YUI *createUI(
bool withThreads )
41 ui =
new YGUI (withThreads);
45 YGUI::YGUI (
bool with_threads)
46 : YUI (with_threads), m_done_init (false), busy_timeout (0)
48 yuiMilestone() <<
"This is libyui-gtk " << VERSION << std::endl;
50 m_no_border = m_fullscreen = m_swsingle =
false;
52 YGUI::setTextdomain( TEXTDOMAIN );
60 topmostConstructorHasFinished();
63 void YGUI::setTextdomain(
const char * domain )
65 bindtextdomain( domain, YSettings::localeDir().c_str() );
66 bind_textdomain_codeset( domain,
"utf8" );
71 extern int _nl_msg_cat_cntr;
76 static void print_log (
const gchar *domain, GLogLevelFlags level,
const gchar *message,
void *pData)
78 YUILogLevel_t ylevel = YUI_LOG_MILESTONE;
80 case G_LOG_LEVEL_ERROR:
81 case G_LOG_LEVEL_CRITICAL:
82 ylevel = YUI_LOG_ERROR;
84 case G_LOG_LEVEL_WARNING:
85 ylevel = YUI_LOG_WARNING;
87 case G_LOG_LEVEL_DEBUG:
88 ylevel = YUI_LOG_DEBUG;
90 case G_LOG_LEVEL_MESSAGE:
91 case G_LOG_LEVEL_INFO:
99 const char *component = domain ? g_intern_string (domain) :
"libyui-gtk";
100 YUILog::instance()->log (ylevel, component,
"libyui-gtk", 0,
"") << message << std::endl;
101 #if 0 // uncomment to put a stop to gdb
102 static int bugStop = 0;
108 void YGUI::checkInit()
115 YCommandLine cmdLine;
116 int argc = cmdLine.argc();
117 char **argv = cmdLine.argv();
118 for (
int i = 1; i < argc; i++) {
119 const char *argp = argv[i];
120 if (argp[0] !=
'-') {
121 if (!strcmp (argp,
"sw_single") || !strcmp (argp,
"online_update"))
126 if (argp[0] ==
'-') argp++;
128 if (!strcmp (argp,
"fullscreen"))
130 else if (!strcmp (argp,
"noborder"))
132 else if (!strcmp (argp,
"help")) {
134 _(
"Command line options for the YaST2 UI (GTK plugin):\n\n"
135 "--noborder no window manager border for main dialogs\n"
136 "--fullscreen use full screen for main dialogs\n"
137 "--nothreads run without additional UI threads\n"
138 "--help prints this help text\n"
145 gtk_init (&argc, &argv);
147 g_log_set_default_handler (print_log, NULL);
148 #if 0 // to crash right away in order to get a stack trace
149 g_log_set_always_fatal (GLogLevelFlags (G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL|
150 G_LOG_LEVEL_WARNING| G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG));
152 std::string themeSubDir = YSettings::themeDir();
154 char* st = getenv(
"Y2STYLE");
155 std::string style = st ? st :
"";
159 style = themeSubDir + style;
163 style = themeSubDir +
"style.css";
166 yuiMilestone() <<
"Style \"" << style <<
"\"\n";
168 GtkCssProvider *provider = gtk_css_provider_new();
169 GFile * file = g_file_new_for_path(style.c_str());
170 if (g_file_query_exists(file, NULL))
172 GError *error = NULL;
173 if (!gtk_css_provider_load_from_file (provider, file, &error))
175 g_printerr (
"%s\n", error->message);
179 GdkDisplay *display = gdk_display_get_default ();
180 GdkScreen *screen = gdk_display_get_default_screen (display);
182 gtk_style_context_add_provider_for_screen (screen,
183 GTK_STYLE_PROVIDER (provider),
184 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
188 yuiMilestone() <<
"Style \"" << style <<
"\" not found. Ignoring style\n";
190 g_object_unref (provider);
192 GdkPixbuf *pixbuf = YGUtils::loadPixbuf (THEMEDIR
"/icons/32x32/apps/yast.png");
194 gtk_window_set_default_icon (pixbuf);
195 g_object_unref (G_OBJECT (pixbuf));
199 static gboolean ycp_wakeup_fn (GIOChannel *source, GIOCondition condition,
206 void YGUI::idleLoop (
int fd_ycp)
214 wakeup = g_io_channel_unix_new (fd_ycp);
215 g_io_channel_set_encoding (wakeup, NULL, NULL);
216 g_io_channel_set_buffered (wakeup, FALSE);
219 guint watch_tag = g_io_add_watch (wakeup, (GIOCondition)(G_IO_IN | G_IO_PRI),
220 ycp_wakeup_fn, &woken);
222 g_main_context_iteration (NULL, TRUE);
224 g_source_remove (watch_tag);
225 g_io_channel_unref (wakeup);
228 static gboolean user_input_timeout_cb (
YGUI *pThis)
230 if (!pThis->pendingEvent())
231 pThis->sendEvent (
new YTimeoutEvent());
236 YEvent *YGUI::waitInput (
unsigned long timeout_ms,
bool block)
239 if (!YDialog::currentDialog (
false))
248 timeout = g_timeout_add (timeout_ms,
249 (GSourceFunc) user_input_timeout_cb,
this);
252 while (!pendingEvent())
253 g_main_context_iteration (NULL, TRUE);
256 while (g_main_context_iteration (NULL, FALSE)) ;
258 YEvent *
event = NULL;
260 event = m_event_handler.consumePendingEvent();
263 g_source_remove (timeout);
267 g_source_remove (busy_timeout);
268 busy_timeout = g_timeout_add (BUSY_CURSOR_TIMEOUT, busy_timeout_cb,
this);
273 void YGUI::sendEvent (YEvent *event)
275 m_event_handler.sendEvent (event);
276 g_main_context_wakeup (NULL);
279 gboolean YGUI::busy_timeout_cb (gpointer data)
283 pThis->busy_timeout = 0;
287 void YGUI::busyCursor()
289 YGDialog *dialog = YGDialog::currentDialog();
291 dialog->busyCursor();
294 void YGUI::normalCursor()
297 g_source_remove (busy_timeout);
301 YGDialog *dialog = YGDialog::currentDialog();
303 dialog->normalCursor();
306 void YGUI::makeScreenShot()
309 YEvent *YGUI::runPkgSelection (YWidget *packageSelector)
311 yuiMilestone() <<
"Running package selection...\n";
315 event = packageSelector->findDialog()->waitForEvent();
316 }
catch (
const std::exception &e) {
317 yuiError() <<
"UI::RunPkgSelection() error: " << e.what() << std::endl;
318 yuiError() <<
"This is a libzypp problem. Do not file a bug against the UI!\n";
320 yuiError() <<
"UI::RunPkgSelection() error (unspecified)\n";
321 yuiError() <<
"This is a libzypp problem. Do not file a bug against the UI!\n";
326 void YGUI::askPlayMacro()
328 std::string filename = askForFileOrDirectory (GTK_FILE_CHOOSER_ACTION_OPEN,
329 DEFAULT_MACRO_FILE_NAME,
"*.ycp", _(
"Open Macro file"));
330 if (!filename.empty()) {
332 YMacro::play (filename);
333 sendEvent (
new YEvent());
337 void YGUI::toggleRecordMacro()
339 if (YMacro::recording()) {
340 YMacro::endRecording();
343 GtkWidget* dialog = gtk_message_dialog_new (NULL,
344 GtkDialogFlags (0), GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
"%s",
345 _(
"Macro recording done."));
346 gtk_dialog_run (GTK_DIALOG (dialog));
347 gtk_widget_destroy (dialog);
350 std::string filename = askForFileOrDirectory (GTK_FILE_CHOOSER_ACTION_SAVE,
351 DEFAULT_MACRO_FILE_NAME,
"*.ycp", _(
"Save Macro"));
352 if (!filename.empty())
353 YMacro::record (filename);
357 void YGUI::askSaveLogs()
359 std::string filename = askForFileOrDirectory (GTK_FILE_CHOOSER_ACTION_SAVE,
360 "/tmp/y2logs.tgz",
"*.tgz *.tar.gz", _(
"Save y2logs"));
361 if (!filename.empty()) {
362 std::string command =
"/usr/sbin/save_y2logs";
363 command +=
" '" + filename +
"'";
364 yuiMilestone() <<
"Saving y2logs: " << command << std::endl;
365 int ret = system (command.c_str());
367 yuiMilestone() <<
"y2logs saved to " << filename << std::endl;
369 char *error = g_strdup_printf (
370 _(
"Could not run: '%s' (exit value: %d)"),
371 command.c_str(), ret);
372 yuiError() << error << std::endl;
381 #define ICONDIR THEMEDIR "/icons/22x22/apps/"
383 YGApplication::YGApplication()
385 setIconBasePath (ICONDIR);
388 void YGApplication::makeScreenShot (
const std::string &_filename)
390 std::string filename (_filename);
391 bool interactive = filename.empty();
393 GtkWidget *widget = GTK_WIDGET (YGDialog::currentWindow());
396 errorMsg (_(
"No dialog to take screenshot of."));
401 gtk_widget_get_allocation(widget, &alloc);
405 gdk_pixbuf_get_from_window (gtk_widget_get_window(widget),
411 errorMsg (_(
"Could not take screenshot."));
418 if (screenShotNameTemplate.empty()) {
420 const char *homedir = getenv(
"HOME");
421 const char *ssdir = getenv(
"Y2SCREENSHOTS");
422 if (!homedir || !strcmp (homedir,
"/")) {
424 dir =
"/tmp/" + (ssdir ? (std::string(ssdir)) : (std::string(
"")));
425 if (mkdir (dir.c_str(), 0700) == -1)
429 dir = homedir + (ssdir ? (
"/" + std::string(ssdir)) : (std::string(
"")));
430 mkdir (dir.c_str(), 0750);
433 screenShotNameTemplate = dir +
"/%s-%03d.png";
437 const char *baseName =
"yast2-";
440 std::map <std::string, int>::iterator it = screenShotNb.find (baseName);
441 if (it == screenShotNb.end())
445 char *tmp_name = g_strdup_printf (screenShotNameTemplate.c_str(), baseName, nb);
449 yuiDebug() <<
"screenshot: " << filename << std::endl;
451 filename = askForFileOrDirectory (
452 GTK_FILE_CHOOSER_ACTION_SAVE,
"",
"*.png", _(
"Save screenshot"));
453 if (filename.empty()) {
454 yuiDebug() <<
"Save screen shot canceled by user\n";
455 goto makeScreenShot_ret;
458 screenShotNb.erase (baseName);
459 screenShotNb[baseName] = nb + 1;
462 yuiDebug() <<
"Saving screen shot to " << filename << std::endl;
463 if (!gdk_pixbuf_save (shot, filename.c_str(),
"png", &error, NULL)) {
464 std::string msg = _(
"Could not save to:");
465 msg +=
" "; msg += filename;
467 msg +=
"\n"; msg +=
"\n";
468 msg += error->message;
470 yuiError() << msg << std::endl;
472 errorMsg (msg.c_str());
473 goto makeScreenShot_ret;
477 g_object_unref (G_OBJECT (shot));
480 void YGApplication::beep()
482 GtkWindow *window = YGDialog::currentWindow();
484 gtk_window_present (window);
485 gtk_widget_error_bell (GTK_WIDGET (window));
494 std::string askForFileOrDirectory (GtkFileChooserAction action,
495 const std::string &path,
const std::string &filter,
const std::string &title)
497 GtkWindow *parent = YGDialog::currentWindow();
500 case GTK_FILE_CHOOSER_ACTION_SAVE:
501 button =
"document-save";
break;
502 case GTK_FILE_CHOOSER_ACTION_OPEN:
503 button =
"folder-open";
break;
504 case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
505 case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
507 button = _(
"Select");
break;
510 dialog = gtk_file_chooser_dialog_new (title.c_str(),
511 parent, action,
"application-exit", GTK_RESPONSE_CANCEL,
512 button, GTK_RESPONSE_ACCEPT, NULL);
513 GtkFileChooser *fileChooser = GTK_FILE_CHOOSER (dialog);
514 gtk_file_chooser_set_local_only (fileChooser, TRUE);
515 gtk_file_chooser_set_do_overwrite_confirmation (fileChooser, TRUE);
518 std::string dirname, filename;
521 yuiWarning() <<
"FileDialog: Relative paths are not supported: '" << path <<
"'\n";
522 else if (!g_file_test (path.c_str(), G_FILE_TEST_EXISTS))
523 yuiWarning() <<
"FileDialog: Path doesn't exist: '" << path <<
"'\n";
524 else if (g_file_test (path.c_str(), G_FILE_TEST_IS_DIR))
527 std::string::size_type i = path.find_last_of (
"/");
528 if (i != std::string::npos) {
529 dirname = path.substr (0, i+1);
530 filename = path.substr (i+1);
535 if (!dirname.empty())
536 gtk_file_chooser_set_current_folder (fileChooser, dirname.c_str());
537 if (!filename.empty())
538 gtk_file_chooser_set_current_name (fileChooser, filename.c_str());
540 if (!filter.empty() && filter !=
"*") {
541 GtkFileFilter *gtk_filter = gtk_file_filter_new();
542 gtk_file_filter_set_name (gtk_filter, filter.c_str());
544 std::istringstream stream (filter);
545 while (!stream.eof()) {
548 if (!str.empty() && str [str.size()-1] ==
',')
549 str.erase (str.size()-1);
550 gtk_file_filter_add_pattern (gtk_filter, str.c_str());
552 gtk_file_chooser_add_filter (fileChooser, gtk_filter);
557 gtk_file_chooser_add_shortcut_folder (fileChooser,
"/", NULL);
560 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
561 gchar *filename = gtk_file_chooser_get_filename (fileChooser);
567 gtk_widget_destroy (dialog);
571 std::string YGApplication::askForExistingDirectory (
572 const std::string &path,
const std::string &title)
573 {
return askForFileOrDirectory (GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, path,
"", title); }
575 std::string YGApplication::askForExistingFile (
576 const std::string &path,
const std::string &filter,
const std::string &title)
577 {
return askForFileOrDirectory (GTK_FILE_CHOOSER_ACTION_OPEN, path, filter, title); }
579 std::string YGApplication::askForSaveFileName (
580 const std::string &path,
const std::string &filter,
const std::string &title)
581 {
return askForFileOrDirectory (GTK_FILE_CHOOSER_ACTION_SAVE, path, filter, title); }
583 std::string YGApplication::glyph (
const std::string &sym)
585 bool reverse = gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL;
586 if (sym == YUIGlyph_ArrowLeft)
587 return reverse ?
"\u25b6" :
"\u25c0";
588 if (sym == YUIGlyph_ArrowRight)
589 return reverse ?
"\u25c0" :
"\u25b6";
590 if (sym == YUIGlyph_ArrowUp)
592 if (sym == YUIGlyph_ArrowDown)
594 if (sym == YUIGlyph_CheckMark)
596 if (sym == YUIGlyph_BulletArrowRight)
597 return reverse ?
"\u21e6" :
"\u279c";
598 if (sym == YUIGlyph_BulletCircle)
600 if (sym == YUIGlyph_BulletSquare)
606 int YGApplication::deviceUnits (YUIDimension dim,
float size)
615 float YGApplication::layoutUnits (YUIDimension dim,
int units)
617 float size = (float) units;
618 if (dim == YD_HORIZ)
return size * (80/640.0);
619 else return size * (25/480.0);
622 static inline GdkScreen *getScreen ()
623 {
return gdk_display_get_default_screen (gdk_display_get_default()); }
626 int YGApplication::displayWidth()
627 {
return gdk_screen_get_width (getScreen()) - 80; }
628 int YGApplication::displayHeight()
629 {
return gdk_screen_get_height (getScreen()) - 80; }
631 int YGApplication::displayDepth()
632 {
return gdk_visual_get_best_depth(); }
634 long YGApplication::displayColors()
635 {
return 1L << displayDepth(); }
639 int YGApplication::defaultWidth() {
return MIN (displayWidth(), 1024); }
640 int YGApplication::defaultHeight() {
return MIN (displayHeight(), 768); }
642 YWidgetFactory *YGUI::createWidgetFactory()
644 YOptionalWidgetFactory *YGUI::createOptionalWidgetFactory()
646 YApplication *YGUI::createApplication()