#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; typedef enum { Profile1, Profile2, Profile3, Profile4, Profile5 } ProfileMode; gchar * fnprofile; gchar * profilefile; gchar * profilefilecontent; gchar * profiles [] = { ".beryl/settings1.Profile", ".beryl/settings2.Profile", ".beryl/settings3.Profile", ".beryl/settings4.Profile", ".beryl/settings5.Profile" }; 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}, }; #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_("Compiz with COW"), "compiz", "--use-cow --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)) 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); } 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 + 4; 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) showMenu(e->button,e->time); 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; } void startApp(GtkWidget * w, gchar * command) { g_spawn_command_line_async(command,NULL); } 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;jCommand,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;i0) { 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+1) 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); mitem = gtk_image_menu_item_new_with_label(_("Beryl Settings Manager")); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mitem), make_image(PIXMAPS_DIR "/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"); 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"); 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 /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=(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= numDM) DM=-1; if (DM==-1) { //we have to find a DM that exists gint i; for (i=0;i