#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "eggtrayicon.h" //intl stuff #include #include #define _(String) gettext (String) #define gettext_noop(String) String #define N_(String) gettext_noop (String) //better error handling #define manager_error(String) g_critical("%s: %s", String, g_strerror(errno)) /* enums for the Beryl options */ typedef enum { AutoBinding, StrictBinding, XGLBinding } BindingMode; typedef enum { AutoCOW, UseCOW, NoCOW } COWMode; typedef enum { AutoRendering, IndirectRendering, XGLRendering } RenderingMode; typedef enum { AutoPlatform, NvidiaPlatform, AIGLXPlatform, XGLPlatform } PlatformMode; typedef enum { AutoRenderPath, TFPRenderPath, CopyRenderPath } RenderPathMode; Atom wmAtom; Atom PopupRunning; GMutex *mutx; EggTrayIcon *mainIcon; GtkWidget *menu; GtkTooltips *tips; /* options for Beryl command line */ RenderPathMode renderPath = AutoRenderPath; PlatformMode platformMode = AutoPlatform; RenderingMode renderingMode = AutoRendering; COWMode cowMode = AutoCOW; BindingMode bindingMode = AutoBinding; gboolean noGLYield = FALSE; gboolean hasMouse = FALSE; gboolean berylLaunched = FALSE; gboolean decoratorLaunched = FALSE; gboolean reloadingBeryl = FALSE; gboolean reloadingDecorator = FALSE; gboolean XGL = FALSE; gboolean NV9XXX = FALSE; gboolean useFB = TRUE; gint WM = 0; gint fallBackWM = 0; gint DM = 0; gint iconsize = 24; gchar *displayname; typedef struct _DMInfo { gchar *Name; gchar *Prog; GtkWidget *Item; } DMInfo; typedef struct _WMInfo { gchar *Name; gchar *Prog; gchar *Opts; gchar *Grep; gint xXGL; // if nonzero, can't use on XGL gint Kill; // if nonzero, means has to be killall'd by its grep-name, and should NOT be xkill'd GtkWidget *Item; GtkWidget *FBItem; } WMInfo; typedef struct _XLSItem { gchar *Command; Window w; } XLSItem; DMInfo DMs[] = { {N_("Standard Beryl Decorator (Emerald)"), "emerald", 0}, {N_("Aquamarine (KDE Decorator)"), "aquamarine", 0}, {N_("Heliodor (GNOME/Metacity Decorator)"), "heliodor", 0}, {N_("Light Themable Decorator (yawd)"), "yawd", 0}, {N_("GTK Window Decorator"), "gtk-window-decorator", 0}, {N_("KDE Window Decorator"), "kde-window-decorator", 0}, }; #define numDM (gint)(sizeof(DMs)/sizeof(DMInfo)) WMInfo WMs[] = { {N_("Beryl"), 0, 0, 0, 0, 0, 0, 0}, {N_("Compiz"), "compiz", "--replace gconf", "compiz", 0, 0, 0, 0}, {N_("Metacity (Gnome Window Manager)"), "metacity", "--replace", "metacity", 0, 0, 0, 0}, {N_("KWin (KDE Window Manager)"), "kwin", "--replace", "kwin", 0, 0, 0, 0}, {N_("xfwm4 (XFCE Window Manager)"), "xfwm4", "", "xfwm4", 0, 1, 0, 0}, {N_("WindowMaker"), "wmaker", "", "WindowMaker", 0, 0, 0, 0}, {N_("FluxBox"), "fluxbox", "", "fluxbox", 1, 1, 0, 0}, {N_("BlackBox"), "blackbox", "", "blackbox", 0, 1, 0, 0}, {N_("OpenBox"), "openbox", "", "openbox", 0, 0, 0, 0}, {N_("IceWM"), "icewm", "", "icewm", 0, 0, 0, 0}, {N_("Enlightenment"), "enlightenment", "", "enlightenment", 0, 1, 0, 0}, }; #define numWM (gint)(sizeof(WMs)/sizeof(WMInfo)) #define FALLBACKWM_OFFSET 2 GtkWidget *useFBItem; GtkWidget *FBSubItem; GtkWidget *DMSubItem; GtkWidget *reloadDecoratorItem; void launchWM(); void startWM(); void init_widgets(); void startBeryl(); void showMenu(guint, guint32); static Window Window_With_Name(Display * dpy, Window top, char *name); static void usage(const char *programName) { printf(_("Usage: %s " "[-d] [--no-force-window-manager] [--no-force-decorator] " "[--help] [--version]" "\n"), programName); } void startApp(GtkWidget * w, gchar * command) { g_spawn_command_line_async(command, NULL); } static void signalHandler(int sig) { static int suspending = 0; switch (sig) { case SIGUSR1: //FIXME, here we should temporarily disable/hide the last "Quit" entry, //Could be missleading to the average user... showMenu(0, gtk_get_current_event_time()); break; case SIGUSR2: if (!suspending) { if (!WM) { WM = fallBackWM + FALLBACKWM_OFFSET; startWM(); suspending = 1; } } else { WM = 0; reloadingBeryl = TRUE; startBeryl(); suspending = 0; } break; default: break; } } gchar *display_part(const gchar * p) { gchar *name = g_strdup(p); gchar *tmp; if ((tmp = g_strrstr(name, ":"))) { *tmp++ = 0; tmp = g_strdup(tmp); g_free(name); name = tmp; } if ((tmp = g_strrstr(name, "."))) { *tmp = 0; } return name; } void beryl_manager_log_handler(const gchar * log_domain, GLogLevelFlags log_level, const gchar * message, gpointer user_data) { g_log_default_handler(log_domain, log_level, message, user_data); if (log_level <= G_LOG_LEVEL_WARNING) return; if (isatty(0)) g_on_error_query(NULL); else abort(); } GSList *parse_xlsclients(gchar * output) { GSList *ret = NULL; gchar *curpos; for (curpos = output; curpos && curpos[0]; curpos = strstr(curpos, "\nWindow")) { XLSItem *i; gchar *p; gchar *q; curpos += 8; i = malloc(sizeof(XLSItem)); i->w = strtol(curpos, NULL, 16); p = strstr(curpos, "Command: "); if (!p) { g_warning(_("Malformed xlsclients, no command?")); free(i); continue; } q = strchr(p, '\n'); if (!q) { g_warning(_("Malformed xlsclients, no command?")); free(i); continue; } q[0] = '\0'; p = g_strdup(p + 10); q[0] = '\n'; //trim p down to its basename q = strchr(p, ' '); if (q) q[0] = '\0'; q = strrchr(p, '/'); if (!q) q = p; else q++; i->Command = g_strdup(q); g_free(p); ret = g_slist_prepend(ret, i); } return ret; } void load_settings() { gchar *path = g_strconcat(g_get_home_dir(), "/.beryl-managerrc", NULL); GKeyFile *f = g_key_file_new(); if (g_key_file_load_from_file(f, path, 0, NULL)) { GError *e = NULL; gint i; gboolean b; i = g_key_file_get_integer(f, "wm-settings", "active_wm", &e); if (!e) WM = i; e = NULL; i = g_key_file_get_integer(f, "wm-settings", "fallback_wm", &e); if (!e) fallBackWM = i; e = NULL; i = g_key_file_get_integer(f, "wm-settings", "active_dm", &e); if (!e) DM = i; e = NULL; b = g_key_file_get_boolean(f, "wm-settings", "use_fallback_wm", &e); if (!e) useFB = b; e = NULL; i = g_key_file_get_integer(f, "wm-settings", "iconsize", &e); if (!e && (i >= 12 && i <= 128)) iconsize = i; e = NULL; i = g_key_file_get_integer(f, "beryl-settings", "render_path", &e); if (!e) renderPath = (RenderPathMode) i; e = NULL; i = g_key_file_get_integer(f, "beryl-settings", "cow_mode", &e); if (!e) cowMode = (COWMode) i; e = NULL; i = g_key_file_get_integer(f, "beryl-settings", "rendering_mode", &e); if (!e) renderingMode = (RenderingMode) i; e = NULL; i = g_key_file_get_integer(f, "beryl-settings", "platform", &e); if (!e) platformMode = (PlatformMode) i; e = NULL; i = g_key_file_get_integer(f, "beryl-settings", "binding", &e); if (!e) bindingMode = (BindingMode) i; e = NULL; if (!XGL && NV9XXX) { b = g_key_file_get_boolean(f, "beryl-settings", "no_gl_yield", &e); if (!e) noGLYield = b; e = NULL; } else noGLYield = FALSE; } g_key_file_free(f); g_free(path); } void save_settings() { gchar *path = g_strconcat(g_get_home_dir(), "/.beryl-managerrc", NULL); gchar *data; GKeyFile *f = g_key_file_new(); g_key_file_set_integer(f, "wm-settings", "active_wm", WM); g_key_file_set_integer(f, "wm-settings", "fallback_wm", fallBackWM); g_key_file_set_integer(f, "wm-settings", "active_dm", DM); g_key_file_set_integer(f, "wm-settings", "iconsize", iconsize); g_key_file_set_boolean(f, "wm-settings", "use_fallback_wm", useFB); g_key_file_set_integer(f, "beryl-settings", "render_path", renderPath); g_key_file_set_integer(f, "beryl-settings", "cow_mode", cowMode); g_key_file_set_integer(f, "beryl-settings", "rendering_mode", renderingMode); g_key_file_set_integer(f, "beryl-settings", "platform", platformMode); g_key_file_set_integer(f, "beryl-settings", "binding", bindingMode); if (!XGL && NV9XXX) g_key_file_set_boolean(f, "beryl-settings", "no_gl_yield", noGLYield); data = g_key_file_to_data(f, NULL, NULL); g_file_set_contents(path, data, -1, NULL); g_key_file_free(f); g_free(path); g_free(data); } gboolean is_running(const gchar * command) { gchar *cmd = g_strconcat("pidof ", command, NULL); gchar *pret; gint i; if (g_spawn_command_line_sync(cmd, &pret, NULL, NULL, NULL)) { g_strchomp(pret); if (pret && *pret) { gchar **pidlist = g_strsplit(pret, " ", 0); i = 0; while (pidlist[i]) { if (atoi(pidlist[i])) { gchar *buffer; gsize len; gchar *file = g_strconcat("/proc/", pidlist[i], "/environ", NULL); if (g_file_get_contents(file, &buffer, &len, NULL)) { gchar *cp; for (cp = buffer; cp < (buffer + len); cp += strlen(cp) + 1) { if (strncmp(cp, "DISPLAY=", 8) == 0) { gchar *part = display_part(cp + 8); if (strcmp(part, displayname) == 0) { g_strfreev(pidlist); g_free(pret); g_free(file); g_free(buffer); g_free(cmd); g_free(part); return TRUE; } g_free(part); } } } g_free(buffer); g_free(file); } i++; } g_strfreev(pidlist); } g_free(pret); } g_free(cmd); return FALSE; } gboolean is_decor_running() { if (DM >= numDM || DM < 0) DM = 0; return (is_running(DMs[DM].Prog)); } void showMenu(guint button, guint32 time) { gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, time); } gboolean popupClient(GtkWidget * w, GdkEventClient * e, gpointer d) { static GdkAtom my_atom = GDK_NONE; if (my_atom == GDK_NONE) my_atom = gdk_atom_intern("beryl-manager-Popup", 1); if (e->message_type == my_atom) { showMenu(0, gtk_get_current_event_time()); return TRUE; } return FALSE; } gboolean buttonUp(GtkWidget * w, GdkEventButton * e, gpointer d) { if (hasMouse && e->button == 3) showMenu(e->button, e->time); return TRUE; } gboolean buttonDown(GtkWidget * w, GdkEventButton * e, gpointer d) { if (hasMouse && e->button == 1 && e->type == 5) startApp(w,"beryl-settings"); return TRUE; } gboolean enterNotify(GtkWidget * w, GdkEventCrossing * e, gpointer d) { hasMouse = TRUE; return TRUE; } gboolean leaveNotify(GtkWidget * w, GdkEventCrossing * e, gpointer d) { hasMouse = FALSE; return TRUE; } gboolean destroyNotify(GtkWidget * w, GdkEventClient * e, gpointer d) { init_widgets(); return TRUE; } gboolean decoratorSignalled(gint signal) { g_warning(_("Decorator caught deadly signal %d"), signal); return FALSE; // terminate for now } gboolean berylSignalled(gint signal) { g_warning(_("Beryl caught deadly signal %d"), signal); return FALSE; // terminate for now } gpointer decorThread(gpointer d) { gint ex = 0; gchar *s = NULL; if (decoratorLaunched && !reloadingDecorator) return NULL; decoratorLaunched = FALSE; s = g_strconcat(DMs[DM].Prog, " --replace", NULL); do { if (g_spawn_command_line_sync(s, NULL, NULL, &ex, NULL)) { decoratorLaunched = TRUE; if (reloadingDecorator) reloadingDecorator = FALSE; } else { g_warning(_("Couldn't launch selected decorator:%s"), DMs[DM].Name); if (WIFEXITED(ex)) // returned something { g_warning(_("decorator %s returned unsuccessfully"), DMs[DM].Name); if (WEXITSTATUS(ex)) // returned something other than 0 { g_warning(_("decorator %s returned with non-zero status"), DMs[DM].Name); } } else if (WIFSIGNALED(ex)) { g_warning(_("decorator %s was killed by a signal"), DMs[DM].Name); if (!decoratorSignalled(WTERMSIG(ex))) { } } } } while (!decoratorLaunched); g_free(s); return NULL; } void killIfWM(XLSItem * i, Display * d) { gint j; for (j = 1; j < numWM; j++) { if (!WMs[j].Kill) { if (strcmp(i->Command, WMs[j].Grep) == 0) { g_message(_("Killing window %x for client %s."), (unsigned int)i->w, WMs[j].Name); XKillClient(d, i->w); } } } } void freeXLS(XLSItem * i, gpointer p) { g_free(i->Command); free(i); } void killWM() { gint killed = 0; if (!g_mutex_trylock(mutx)) return; { Display *d = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); XLockDisplay(d); { gint i; for (i = 1; i < numWM; i++) { if (WMs[i].Kill) { gchar *pret; gchar *cm = g_strconcat("pidof ", WMs[i].Grep, NULL); if (!g_spawn_command_line_sync (cm, &pret, NULL, NULL, NULL)) g_warning(_("No pidof, this may not work right.")); else { g_strchomp(pret); if (pret) { gchar *cret; if (strlen(pret)) { if (pret[strlen(pret) - 1] == '\n') pret[strlen(pret) - 1] = '\0'; for (cret = pret - 1; cret; cret = strchr(cret, ' ')) { gchar *p; gchar *e; gchar *f; pid_t pid; gsize l; cret++; p = strchr(cret, ' '); if (p) p[0] = '\0'; f = g_strdup_printf("/proc/%s/environ", cret); pid = strtol(cret, NULL, 10); if (p) p[0] = ' '; if (g_file_get_contents(f, &e, &l, NULL)) { gchar *cp; for (cp = e; (cp - e) < l; cp += strlen(cp) + 1) { if (strncmp(cp, "DISPLAY=", 8) == 0) { //might be killable gchar *md = display_part(cp + 8); if (strcmp(md, displayname) == 0) { //on same display, go ahead kill if (kill(pid, SIGTERM) != -1) killed++; } g_free(md); } } g_free(e); } else { g_warning("Couldn't open %s", f); } g_free(f); } } g_free(pret); } } g_free(cm); } } Window w = wmAtom ? XGetSelectionOwner(d, wmAtom) : None; if (w != None) XKillClient(d, w); else if (killed) { gchar *cli; GSList *xls; g_warning(_ ("Couldn't find a Selection Owner, perhaps no WM running?\nOtherwise, manually kill your wm, and report the bug to the developers, it doesn't follow the standards.\nFalling back to looking for a defined WM in xlsclients.")); if (!g_spawn_command_line_sync ("xlsclients -l", &cli, NULL, NULL, NULL)) { g_warning(_("No xlsclients, this may not work right.")); } else { if (!cli) manager_error(_ ("No output from xlsclients, bailing.")); xls = parse_xlsclients(cli); g_free(cli); g_slist_foreach(xls, (GFunc) killIfWM, d); g_slist_foreach(xls, (GFunc) freeXLS, NULL); g_slist_free(xls); } } XSync(d, FALSE); } XUnlockDisplay(d); } g_mutex_unlock(mutx); } void startWM() { gchar *wm_command = g_strjoin(" ", WMs[WM].Prog, WMs[WM].Opts, NULL); berylLaunched = FALSE; killWM(); g_spawn_command_line_async(wm_command, NULL); g_free(wm_command); } #define BERYL_COMMAND_LINE_SIZE 150 gpointer berylThread(gpointer d) { gint ex = 0; gchar beryl_command[BERYL_COMMAND_LINE_SIZE]; if (XGL) g_strlcpy(beryl_command, "beryl-xgl", BERYL_COMMAND_LINE_SIZE); else g_strlcpy(beryl_command, "beryl", BERYL_COMMAND_LINE_SIZE); switch (renderPath) { case TFPRenderPath: g_strlcat(beryl_command, " --use-tfp", BERYL_COMMAND_LINE_SIZE); break; case CopyRenderPath: g_strlcat(beryl_command, " --use-copy", BERYL_COMMAND_LINE_SIZE); break; default: break; } switch (renderingMode) { case IndirectRendering: g_strlcat(beryl_command, " --indirect-rendering", BERYL_COMMAND_LINE_SIZE); break; case XGLRendering: g_strlcat(beryl_command, " --xgl-rendering", BERYL_COMMAND_LINE_SIZE); break; default: break; } switch (cowMode) { case UseCOW: g_strlcat(beryl_command, " --use-cow", BERYL_COMMAND_LINE_SIZE); break; case NoCOW: g_strlcat(beryl_command, " --no-cow", BERYL_COMMAND_LINE_SIZE); break; default: break; } switch (platformMode) { case AIGLXPlatform: g_strlcat(beryl_command, " --force-aiglx", BERYL_COMMAND_LINE_SIZE); break; case NvidiaPlatform: g_strlcat(beryl_command, " --force-nvidia", BERYL_COMMAND_LINE_SIZE); break; case XGLPlatform: g_strlcat(beryl_command, " --force-xgl", BERYL_COMMAND_LINE_SIZE); break; default: break; } switch (bindingMode) { case StrictBinding: g_strlcat(beryl_command, " --strict-binding", BERYL_COMMAND_LINE_SIZE); break; case XGLBinding: g_strlcat(beryl_command, " --xgl-binding", BERYL_COMMAND_LINE_SIZE); break; default: break; } if (noGLYield) g_strlcat(beryl_command, " --skip-gl-yield", BERYL_COMMAND_LINE_SIZE); berylLaunched = TRUE; while (berylLaunched) { killWM(); if (!g_spawn_command_line_sync(beryl_command, NULL, NULL, &ex, NULL)) { if (XGL) manager_error(_("can't execute beryl-xgl")); else manager_error(_("can't execute beryl")); } if (reloadingBeryl) { reloadingBeryl = FALSE; return NULL; } else if (WIFEXITED(ex)) // returned something { if (WEXITSTATUS(ex)) // returned something other than 0 { berylLaunched = FALSE; } } else if (WIFSIGNALED(ex)) // killed by a signal { if (!berylSignalled(WTERMSIG(ex))) { berylLaunched = FALSE; } } } //if this thread exits, and WM is still beryl, fall back into the fall back WM if (WM == 0 && useFB) { WM = fallBackWM + FALLBACKWM_OFFSET; gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(WMs[WM].Item), TRUE); //gtk_widget_set_sensitive(useFBItem,FALSE); gtk_widget_set_sensitive(DMSubItem, FALSE); gtk_widget_set_sensitive(reloadDecoratorItem, FALSE); //gtk_widget_set_sensitive(FBSubItem,FALSE); //for(ex=1;ex 0) { nam = WMs[wm].Grep; return is_running(nam); } else { return is_running("beryl") || is_running("beryl-xgl") || is_running("compiz"); } } gboolean detect_app(const gchar * app) { gint ex; gchar *f = g_strdup_printf("sh -c 'which %s > /dev/null 2>&1'", app); if (!g_spawn_command_line_sync(f, NULL, NULL, &ex, NULL)) manager_error(_("can't use this app, no which")); g_free(f); if (WIFEXITED(ex)) { if (WEXITSTATUS(ex) == 0) return TRUE; } else manager_error(_("something went wrong with which")); return FALSE; } gboolean detect_wm(gint wm) { if (!XGL || !WMs[wm].xXGL) { if (detect_app(WMs[wm].Prog)) return TRUE; } if (wm == WM) WM = -1; if (wm == fallBackWM + FALLBACKWM_OFFSET) fallBackWM = -1; return FALSE; } gboolean detect_dm(gint dm) { if (detect_app(DMs[dm].Prog)) return TRUE; if (dm == DM) DM = -1; return FALSE; } void setGLYield(GtkWidget * w, gpointer p) { noGLYield = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)); save_settings(); if (WM == 0) reloadBeryl(); } GtkWidget *add_menu_group_item(GtkWidget * menu, GSList ** group, const gchar * name, gboolean show, gboolean check, GCallback callback, gpointer data) { GtkWidget *mitem; mitem = gtk_radio_menu_item_new_with_label(*group, name); *group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mitem)); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), check); if (show) gtk_widget_show(mitem); else gtk_widget_hide(mitem); g_signal_connect(mitem, "toggled", callback, data); return mitem; } void init_menu() { GtkWidget *submenu; GtkWidget *mitem; GtkWidget *smshell; GSList *renderPathGroup = NULL; GSList *cowGroup = NULL; GSList *platformGroup = NULL; GSList *bindingGroup = NULL; GSList *renderingGroup = NULL; GSList *wms = NULL; GSList *fbk = NULL; GSList *dms = NULL; gint i; menu = gtk_menu_new(); g_object_ref(menu); if (detect_app("beryl-settings")) { mitem = gtk_image_menu_item_new_with_label(_("Beryl Settings Manager")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem), make_image(DATADIR "/icons/hicolor/scalable/apps/beryl-settings.svg")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); g_signal_connect(mitem, "activate", G_CALLBACK(startApp), "beryl-settings"); } if (detect_app("emerald-theme-manager")) { mitem = gtk_image_menu_item_new_with_label(_("Emerald Theme Manager")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem), make_image(PIXMAPS_DIR "/emerald-theme-manager-icon.png")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); g_signal_connect(mitem, "activate", G_CALLBACK(startApp), "emerald-theme-manager"); } if (detect_app("emerald-theme-manager") || detect_app("beryl-settings")) { mitem = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); } mitem = gtk_image_menu_item_new_with_label(_("Reload Window Manager")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU)); g_signal_connect(mitem, "activate", G_CALLBACK(reloadWM), NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); mitem = gtk_image_menu_item_new_with_label(_("Select Window Manager")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem), make_image(PIXMAPS_DIR "/wm-select.png")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); smshell = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell); for (i = 0; i < numWM; i++) { mitem = add_menu_group_item(smshell, &wms, gettext(WMs[i].Name), ((i == 0) || detect_wm(i)), (i == WM), G_CALLBACK(setWM), GINT_TO_POINTER(i)); WMs[i].Item = mitem; } mitem = gtk_image_menu_item_new_with_label(_("Advanced Beryl options")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); submenu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), submenu); mitem = gtk_image_menu_item_new_with_label(_("Rendering path")); gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem); gtk_widget_show(mitem); smshell = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell); add_menu_group_item(smshell, &renderPathGroup, _("Automatic"), TRUE, (renderPath == AutoRenderPath), G_CALLBACK(toggleRenderingPath), GINT_TO_POINTER(AutoRenderPath)); add_menu_group_item(smshell, &renderPathGroup, _("Texture From Pixmap"), TRUE, (renderPath == TFPRenderPath), G_CALLBACK(toggleRenderingPath), GINT_TO_POINTER(TFPRenderPath)); add_menu_group_item(smshell, &renderPathGroup, _("Copy"), TRUE, (renderPath == CopyRenderPath), G_CALLBACK(toggleRenderingPath), GINT_TO_POINTER(CopyRenderPath)); mitem = gtk_image_menu_item_new_with_label(_("Composite Overlay Window")); gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem); gtk_widget_show(mitem); smshell = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell); add_menu_group_item(smshell, &cowGroup, _("Automatic"), TRUE, (cowMode == AutoCOW), G_CALLBACK(toggleCOW), GINT_TO_POINTER(AutoCOW)); add_menu_group_item(smshell, &cowGroup, _("Use COW"), TRUE, (cowMode == UseCOW), G_CALLBACK(toggleCOW), GINT_TO_POINTER(UseCOW)); add_menu_group_item(smshell, &cowGroup, _("Don't use COW"), TRUE, (cowMode == NoCOW), G_CALLBACK(toggleCOW), GINT_TO_POINTER(NoCOW)); mitem = gtk_image_menu_item_new_with_label(_("Rendering platform")); gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem); gtk_widget_show(mitem); smshell = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell); add_menu_group_item(smshell, &platformGroup, _("Automatic"), TRUE, (platformMode == AutoPlatform), G_CALLBACK(togglePlatform), GINT_TO_POINTER(AutoPlatform)); add_menu_group_item(smshell, &platformGroup, _("Force Nvidia"), TRUE, (platformMode == NvidiaPlatform), G_CALLBACK(togglePlatform), GINT_TO_POINTER(NvidiaPlatform)); add_menu_group_item(smshell, &platformGroup, _("Force AIGLX"), TRUE, (platformMode == AIGLXPlatform), G_CALLBACK(togglePlatform), GINT_TO_POINTER(AIGLXPlatform)); add_menu_group_item(smshell, &platformGroup, _("Force XGL"), TRUE, (platformMode == XGLPlatform), G_CALLBACK(togglePlatform), GINT_TO_POINTER(XGLPlatform)); mitem = gtk_image_menu_item_new_with_label(_("Binding")); gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem); gtk_widget_show(mitem); smshell = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell); add_menu_group_item(smshell, &bindingGroup, _("Automatic"), TRUE, (bindingMode == AutoBinding), G_CALLBACK(toggleBinding), GINT_TO_POINTER(AutoBinding)); add_menu_group_item(smshell, &bindingGroup, _("Strict Binding"), TRUE, (bindingMode == StrictBinding), G_CALLBACK(toggleBinding), GINT_TO_POINTER(StrictBinding)); add_menu_group_item(smshell, &bindingGroup, _("XGL Binding"), TRUE, (bindingMode == XGLBinding), G_CALLBACK(toggleBinding), GINT_TO_POINTER(XGLBinding)); mitem = gtk_image_menu_item_new_with_label(_("Rendering")); gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem); gtk_widget_show(mitem); smshell = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell); add_menu_group_item(smshell, &renderingGroup, _("Automatic"), TRUE, (renderingMode == AutoRendering), G_CALLBACK(toggleRendering), GINT_TO_POINTER(AutoRendering)); add_menu_group_item(smshell, &renderingGroup, _("Indirect Rendering"), TRUE, (renderingMode == IndirectRendering), G_CALLBACK(toggleRendering), GINT_TO_POINTER(IndirectRendering)); add_menu_group_item(smshell, &renderingGroup, _("XGL Rendering"), TRUE, (renderingMode == XGLRendering), G_CALLBACK(toggleRendering), GINT_TO_POINTER(XGLRendering)); if (!XGL && NV9XXX) { mitem = gtk_check_menu_item_new_with_label(_ ("Disable GL Yield setting\n" "Use this to fix some redraw bugs")); gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), noGLYield); gtk_widget_show(mitem); g_signal_connect(mitem, "toggled", G_CALLBACK(setGLYield), NULL); } mitem = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); mitem = gtk_image_menu_item_new_with_label(_("Reload Window Decorator")); reloadDecoratorItem = mitem; gtk_widget_set_sensitive(reloadDecoratorItem, WM < 3); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU)); g_signal_connect(mitem, "activate", G_CALLBACK(reloadDecorator), NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); mitem = gtk_image_menu_item_new_with_label(_("Select Window Decorator")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem), make_image(PIXMAPS_DIR "/wd-select.png")); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); smshell = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell); DMSubItem = mitem; gtk_widget_set_sensitive(GTK_WIDGET(DMSubItem), WM < 3); for (i = 0; i < numDM; i++) { mitem = gtk_radio_menu_item_new_with_label(dms, gettext(DMs[i].Name)); dms = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mitem)); if (i == DM) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), TRUE); gtk_menu_shell_append(GTK_MENU_SHELL(smshell), mitem); if (detect_dm(i)) gtk_widget_show(mitem); else gtk_widget_hide(mitem); g_signal_connect(mitem, "toggled", G_CALLBACK(setDM), GINT_TO_POINTER(i)); DMs[i].Item = mitem; } mitem = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); mitem = gtk_check_menu_item_new_with_label(_ ("Launch Fall-back Window\nManager if beryl crashes")); useFBItem = mitem; gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), useFB); g_signal_connect(mitem, "toggled", G_CALLBACK(toggleFB), NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); mitem = gtk_image_menu_item_new_with_label(_ ("Select Fall-back Window Manager")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem), make_image(PIXMAPS_DIR "/fall-back-wm-select.png")); FBSubItem = mitem; gtk_widget_set_sensitive(FBSubItem, useFB); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); smshell = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), smshell); for (i = FALLBACKWM_OFFSET; i < numWM; i++) { mitem = gtk_radio_menu_item_new_with_label(fbk, gettext(WMs[i].Name)); fbk = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mitem)); if ((i - FALLBACKWM_OFFSET) == fallBackWM) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), TRUE); gtk_widget_set_sensitive(mitem, useFB); gtk_menu_shell_append(GTK_MENU_SHELL(smshell), mitem); if (detect_wm(i)) gtk_widget_show(mitem); else gtk_widget_hide(mitem); WMs[i].FBItem = mitem; g_signal_connect(mitem, "toggled", G_CALLBACK(setFallbackWM), GINT_TO_POINTER(i - FALLBACKWM_OFFSET)); } mitem = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); mitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); g_signal_connect(mitem, "activate", G_CALLBACK(quitMe), NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem); gtk_widget_show(mitem); } void init_widgets() { GtkWidget *icon; GtkWidget *evbox; GdkPixbuf *pbuf; tips = gtk_tooltips_new(); mainIcon = egg_tray_icon_new(_("Beryl Manager")); evbox = gtk_event_box_new(); gtk_event_box_set_visible_window(GTK_EVENT_BOX(evbox), FALSE); gtk_tooltips_set_tip(tips, evbox, _("Beryl Manager"), _("Manage various things related to Beryl")); pbuf = gdk_pixbuf_new_from_file_at_size(DATADIR "/icons/hicolor/scalable/apps/beryl-manager.svg", iconsize, iconsize, NULL); if (!pbuf) pbuf = gdk_pixbuf_new_from_file(DATADIR "/icons/hicolor/24x24/apps/beryl-manager.png", NULL); if (!pbuf) pbuf = gdk_pixbuf_new_from_file(PIXMAPS_DIR "/beryl-manager.png", NULL); if (!pbuf) icon = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_SMALL_TOOLBAR); else { g_object_ref(G_OBJECT(pbuf)); icon = gtk_image_new_from_pixbuf(pbuf); } gtk_container_add(GTK_CONTAINER(mainIcon), evbox); gtk_container_add(GTK_CONTAINER(evbox), icon); g_signal_connect(evbox, "button-release-event", G_CALLBACK(buttonUp), NULL); g_signal_connect(evbox, "button-press-event", G_CALLBACK(buttonDown), NULL); g_signal_connect(evbox, "enter-notify-event", G_CALLBACK(enterNotify), NULL); g_signal_connect(evbox, "leave-notify-event", G_CALLBACK(leaveNotify), NULL); g_signal_connect(evbox, "destroy", G_CALLBACK(destroyNotify), NULL); g_signal_connect(mainIcon, "client-event", G_CALLBACK(popupClient), NULL); gtk_widget_show_all(GTK_WIDGET(mainIcon)); } void detect_nvidia() { //find out if we have XGL gint ex = 0; if (!g_spawn_command_line_sync ("sh -c 'glxinfo | grep -i NVIDIA > /dev/null'", NULL, NULL, &ex, NULL)) manager_error(_("can't use this app, no glxinfo or no grep")); if (WIFEXITED(ex)) { if (WEXITSTATUS(ex) == 0) NV9XXX = TRUE; else NV9XXX = FALSE; } else manager_error(_("something went wrong with glxinfo or grep")); } void detect_xgl() { //find out if we have XGL gint ex = 0; if (!g_spawn_command_line_sync("sh -c 'xvinfo | grep -i Xgl > /dev/null'", NULL, NULL, &ex, NULL)) manager_error(_("can't use this app, no xvinfo or no grep")); if (WIFEXITED(ex)) { if (WEXITSTATUS(ex) == 0) XGL = TRUE; else XGL = FALSE; } else manager_error(_("something went wrong with xvinfo or grep")); } int main(int argc, char **argv) { gint i, found; gchar *buffer; gboolean daemon_mode = TRUE; Display *d; gboolean force_window_manager = TRUE; gboolean force_decorator = TRUE; Window running_window; //Intialise error handler g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING | G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL, beryl_manager_log_handler, NULL); //set the locale stuff setlocale(LC_ALL, ""); bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); textdomain(GETTEXT_PACKAGE); //parse command line arguments for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--help") == 0) { usage(argv[0]); return 0; } else if (strcmp(argv[i], "--version") == 0) { printf(PACKAGE_STRING "\n"); return 0; } else if (strcmp(argv[i], "-d") == 0) { daemon_mode = FALSE; } else if (strcmp(argv[i], "--no-force-window-manager") == 0) { force_window_manager = FALSE; } else if (strcmp(argv[i], "--no-force-decorator") == 0) { force_decorator = FALSE; } else { usage(argv[0]); return 1; } } //detach from console or not if (daemon_mode) { daemon(1, 1); close(0); } if (!XInitThreads()) { g_warning(_("Can't init XLib thread support")); return 3; } d = XOpenDisplay(NULL); if ((running_window = Window_With_Name(d, DefaultRootWindow(d), // GDK_WINDOW_XID( // gdk_get_default_root_window() // ), "Beryl Manager"))) // "Event Tester"))) { XEvent clientEvent; gboolean missed = FALSE; PopupRunning = XInternAtom(d, "beryl-manager-Popup", 0); clientEvent.xclient.type = ClientMessage; clientEvent.xclient.window = running_window; clientEvent.xclient.message_type = PopupRunning; clientEvent.xclient.format = 32; clientEvent.xclient.display = d; clientEvent.xclient.data.l[0] = 0; clientEvent.xclient.data.l[1] = 0; clientEvent.xclient.data.l[2] = 0; clientEvent.xclient.data.l[3] = 0; clientEvent.xclient.data.l[4] = 0; // gdk_error_trap_push (); missed = XSendEvent(d, running_window, False, NoEventMask, &clientEvent); XSync(d, False); // gdk_error_trap_pop (); return 0; } XCloseDisplay(d); // Some warning about changed behaviour for the unaware user /* if (!force_window_manager && !force_decorator) { if (!strcmp (PACKAGE_VERSION, "0.1.1")) { fprintf(stderr, "beryl-manager doesn't autostart window-manager/decorator\n" "any more. Please consult: man beryl-manager\n\n"); } } */ //taken out because starting beryl is -the- reason for beryl-manager's existence. gtk_init(&argc, &argv); d = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); buffer = g_strdup(DisplayString (gdk_x11_display_get_xdisplay (gdk_display_get_default()))); if (buffer) { displayname = display_part(buffer); g_free(buffer); } if (!g_thread_supported()) g_thread_init(NULL); gdk_threads_init(); gdk_threads_enter(); mutx = g_mutex_new(); // Check for the windows manager buffer = g_strconcat("WM_S", displayname, NULL); wmAtom = XInternAtom(d, buffer, 0); g_free(buffer); detect_xgl(); if (!XGL) detect_nvidia(); load_settings(); init_widgets(); init_menu(); if (WM < 0 || WM >= (numWM)) WM = -1; if (WM == -1) { //set WM to beryl for now gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(WMs[0].Item), TRUE); } if (fallBackWM < 0 || fallBackWM > (numWM - 1)) fallBackWM = -1; if (fallBackWM == -1) { //we have to find a fall back WM that exists gint i; for (i = 1; i < numWM; i++) { if (detect_wm(i)) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM (WMs[i].FBItem), TRUE); fallBackWM = i - FALLBACKWM_OFFSET; break; } } } if (fallBackWM == -1) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(useFBItem), FALSE); if (DM < 0 || DM >= numDM) DM = -1; if (DM == -1) { //we have to find a DM that exists gint i; for (i = 0; i < numDM; i++) { if (detect_dm(i)) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM (DMs[i].Item), TRUE); DM = i; break; } } } if (DM == -1) manager_error("No Display Manager Found!"); save_settings(); found = False; for (i = 0; i < numDM && !found; i++) { if (is_running(DMs[i].Prog)) found = True; } if (!found || (force_decorator && !is_decor_running())) { g_thread_create(decorThread, NULL, FALSE, NULL); // launch decorator } if (!force_window_manager) { found = False; for (i = 0; i < numWM && !found; i++) if (is_wm_running(i)) found = True; if (!found) launchWM(); } else if (!is_wm_running(WM)) { launchWM(); } signal(SIGUSR1, signalHandler); signal(SIGUSR2, signalHandler); gtk_main(); gdk_threads_leave(); g_free(displayname); return 0; } /* - - - - - - - - - * [These functions are from the file "dsimple.c" used with xwininfo.] * * Written by Mark Lillibridge. Last updated 7/1/87 * * * Window_With_Name: routine to locate a window with a given name on a display. * If no window with the given name is found, 0 is returned. * If more than one window has the given name, the first * one found will be returned. Only top and its subwindows * are looked at. Normally, top should be the Root Window. */ static Window Window_With_Name(Display * dpy, Window top, char *name) { Window *children, dummy; unsigned int nchildren; unsigned i; Window w = 0; char *window_name; if (XFetchName(dpy, top, &window_name) && !strcmp(window_name, name)) { XFree(window_name); return (top); } XFree(window_name); if (!XQueryTree(dpy, top, &dummy, &dummy, &children, &nchildren)) return (0); for (i = 0; i < nchildren; i++) { w = Window_With_Name(dpy, children[i], name); if (w) break; } if (children) XFree((char *)children); return (w); }