123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526 |
- /*
- * wmfs.c
- * Copyright © 2008, 2009 Martin Duquesnoy <xorg62@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of the nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "wmfs.h"
- int
- errorhandler(Display *d, XErrorEvent *event)
- {
- char mess[256];
- Client *c;
- /* Check if there is another WM running */
- if(BadAccess == event->error_code
- && ROOT == event->resourceid)
- errx(EXIT_FAILURE, "Another Window Manager is already running.");
- /* Ignore focus change error for unmapped client */
- /* Too lazy to add Xproto.h so:
- * 42 = X_SetInputFocus
- * 28 = X_GrabButton
- */
- if((c = client_gb_win(event->resourceid)))
- if(event->error_code == BadWindow
- || event->request_code == 42
- || event->request_code == 28)
- return 0;
- XGetErrorText(d, event->error_code, mess, 128);
- warnx("%s(%d) opcodes %d/%d\n resource #%lx\n", mess,
- event->error_code,
- event->request_code,
- event->minor_code,
- event->resourceid);
- return 1;
- }
- int
- errorhandlerdummy(Display *d, XErrorEvent *event)
- {
- return 0;
- }
- /** Clean wmfs before the exit
- */
- void
- quit(void)
- {
- Client *c;
- int i;
- /* Set the silent error handler */
- XSetErrorHandler(errorhandlerdummy);
- /* Unmanage all clients */
- for(c = clients; c; c = c->next)
- {
- client_unhide(c);
- XReparentWindow(dpy, c->win, ROOT, c->geo.x, c->geo.y);
- }
- IFREE(tags);
- IFREE(seltag);
- XftFontClose(dpy, font);
- for(i = 0; i < CurLast; ++i)
- XFreeCursor(dpy, cursor[i]);
- XFreeGC(dpy, gc_stipple);
- infobar_destroy();
- IFREE(sgeo);
- IFREE(spgeo);
- IFREE(infobar);
- IFREE(keys);
- IFREE(func_list);
- IFREE(layout_list);
- IFREE(net_atom);
- /* Clean conf alloced thing */
- IFREE(menulayout.item);
- if(conf.menu)
- {
- for(i = 0; i < LEN(conf.menu); ++i)
- IFREE(conf.menu[i].item);
- IFREE(conf.menu);
- }
- IFREE(conf.launcher);
- IFREE(conf.ntag);
- IFREE(conf.titlebar.mouse);
- for(i = 0; i < conf.titlebar.nbutton; ++i)
- {
- IFREE(conf.titlebar.button[i].mouse);
- IFREE(conf.titlebar.button[i].linecoord);
- }
- IFREE(conf.bars.mouse);
- IFREE(conf.titlebar.button);
- IFREE(conf.client.mouse);
- IFREE(conf.root.mouse);
- XSync(dpy, False);
- XCloseDisplay(dpy);
- return;
- }
- void *
- thread_process(void *arg)
- {
- XEvent ev;
- /* X event loop */
- if(!(int*)arg)
- {
- while(!exiting && !XNextEvent(dpy, &ev))
- getevent(ev);
- pthread_exit(0);
- }
- /* Status checking loop with timing */
- else
- {
- while(!exiting)
- {
- spawn(status_path);
- sleep(conf.status_timing);
- }
- pthread_exit(0);
- }
- }
- /** WMFS main loop.
- */
- void
- mainloop(void)
- {
- XEvent ev;
- pthread_t evloop, evstatus;
- void *ret;
- if(!estatus)
- while(!exiting && !XNextEvent(dpy, &ev))
- getevent(ev);
- else
- {
- pthread_create(&evloop, NULL, thread_process, "1");
- pthread_create(&evstatus, NULL, thread_process, NULL);
- (void)pthread_join(evloop, &ret);
- (void)pthread_join(evstatus, &ret);
- }
- return;
- }
- /** Set the exiting variable to True
- * for stop the main loop
- * \param cmd unused uicb_t
- */
- void
- uicb_quit(uicb_t cmd)
- {
- exiting = True;
- return;
- }
- /** Scan if there are windows on X
- * for manage it
- */
- void
- scan(void)
- {
- uint i, n;
- XWindowAttributes wa;
- Window usl, usl2, *w = NULL;
- Atom rt;
- int rf, tag = -1, screen = -1, free = -1;
- ulong ir, il;
- uchar *ret;
- Client *c;
- if(XQueryTree(dpy, ROOT, &usl, &usl2, &w, &n))
- for(i = n - 1; i != -1; --i)
- if(XGetWindowAttributes(dpy, w[i], &wa)
- && !(wa.override_redirect || XGetTransientForHint(dpy, w[i], &usl))
- && wa.map_state == IsViewable)
- {
- if(XGetWindowProperty(dpy, w[i], ATOM("_WMFS_TAG"), 0, 32,
- False, XA_CARDINAL, &rt, &rf, &ir, &il, &ret) == Success && ret)
- {
- tag = *ret;
- XFree(ret);
- }
- if(XGetWindowProperty(dpy, w[i], ATOM("_WMFS_SCREEN"), 0, 32,
- False, XA_CARDINAL, &rt, &rf, &ir, &il, &ret) == Success && ret)
- {
- screen = *ret;
- XFree(ret);
- }
- if(XGetWindowProperty(dpy, w[i], ATOM("_WMFS_ISFREE"), 0, 32,
- False, XA_CARDINAL, &rt, &rf, &ir, &il, &ret) == Success && ret)
- {
- free = *ret;
- XFree(ret);
- }
- c = client_manage(w[i], &wa, False);
- if(tag != -1)
- c->tag = tag;
- if(screen != -1 && screen <= screen_count() - 1)
- c->screen = screen;
- if(free != -1)
- c->flags |= (free) ? FreeFlag : 0;
- client_update_attributes(c);
- }
- /* Set update layout request */
- for(c = clients; c; c = c->next)
- {
- if(c->tag > conf.ntag[c->screen])
- c->tag = conf.ntag[c->screen];
- tags[c->screen][c->tag].request_update = True;
- }
- for(i = 0; i < screen_count(); ++i)
- arrange(i, True);
- XFree(w);
- return;
- }
- /** Reload the WMFS with the new configuration
- * file changement *TESTING*
- */
- void
- uicb_reload(uicb_t cmd)
- {
- quit();
- for(; argv_global[0] && argv_global[0] == ' '; ++argv_global);
- execlp(argv_global, argv_global, NULL);
- return;
- }
- /** Check if wmfs is running (for functions that will be
- execute when wmfs will be already running).
- \return False if wmfs is not running
- */
- Bool
- check_wmfs_running(void)
- {
- Atom rt;
- int rf;
- ulong ir, il;
- uchar *ret;
- XGetWindowProperty(dpy, ROOT, ATOM("_WMFS_RUNNING"), 0L, 4096,
- False, XA_CARDINAL, &rt, &rf, &ir, &il, &ret);
- if(!ret)
- {
- XFree(ret);
- warnx("Wmfs is not running. (_WMFS_RUNNING not present)");
- return False;
- }
- XFree(ret);
- return True;
- }
- /** Execute an uicb function
- *\param func Function name
- *\param cmd Function's command
- *\return 0 if there is an error
- */
- void
- exec_uicb_function(char *func, char *cmd)
- {
- long data[5];
- /* Check if wmfs is running (this function is executed when wmfs
- is already running normally...) */
- if(!check_wmfs_running())
- return;
- data[4] = True;
- XChangeProperty(dpy, ROOT, ATOM("_WMFS_FUNCTION"), ATOM("UTF8_STRING"),
- 8, PropModeReplace, (uchar*)func, strlen(func));
- if(cmd == NULL)
- cmd = "";
- XChangeProperty(dpy, ROOT, ATOM("_WMFS_CMD"), ATOM("UTF8_STRING"),
- 8, PropModeReplace, (uchar*)cmd, strlen(cmd));
- send_client_event(data, "_WMFS_FUNCTION");
- return;
- }
- /** Set statustext
- *\param str Statustext string
- */
- void
- set_statustext(int s, char *str)
- {
- int i;
- long data[5];
- char atom_name[64];
- data[4] = True;
- if(!str)
- return;
- if(s == -1)
- {
- for(i = 0; i < screen_count(); ++i)
- {
- sprintf(atom_name, "_WMFS_STATUSTEXT_%d", i);
- XChangeProperty(dpy, ROOT, ATOM(atom_name), ATOM("UTF8_STRING"),
- 8, PropModeReplace, (uchar*)str, strlen(str));
- send_client_event(data, atom_name);
- }
- }
- else
- {
- sprintf(atom_name, "_WMFS_STATUSTEXT_%d", s);
- XChangeProperty(dpy, ROOT, ATOM(atom_name), ATOM("UTF8_STRING"),
- 8, PropModeReplace, (uchar*)str, strlen(str));
- send_client_event(data, atom_name);
- }
- return;
- }
- /** Update status script by ewmh hint
- */
- void
- update_status(void)
- {
- long data[5];
- if(!check_wmfs_running())
- return;
- data[4] = True;
- send_client_event(data, "_WMFS_UPDATE_STATUS");
- return;
- }
- /** Signal handle function
- */
- void
- signal_handle(int sig)
- {
- exiting = True;
- quit();
- exit(EXIT_SUCCESS);
- return;
- }
- /** main function
- * \param argc ?
- * \param argv ?
- * \return 0
- */
- int
- main(int argc, char **argv)
- {
- int i;
- char *ol = "csgVS";
- argv_global = _strdup(argv[0]);
- sprintf(conf.confpath, "%s/"DEF_CONF, getenv("HOME"));
- while((i = getopt(argc, argv, "hviSc:s:g:C:V:")) != -1)
- {
- /* For options who need WMFS running */
- if(strchr(ol, i) && !(dpy = XOpenDisplay(NULL)))
- errx(EXIT_FAILURE, "cannot open X server.");
- switch(i)
- {
- case 'h':
- default:
- printf("usage: %s [-ihvS] [-C <file>] [-c <uicb function> <cmd> ] [-g <argument>] [-s <screen_num> <string>] [-V <viwmfs cmd]\n"
- " -C <file> Load a configuration file\n"
- " -c <uicb_function> <cmd> Execute an uicb function to control WMFS\n"
- " -g <argument> Show information about wmfs status\n"
- " -s <screen_num> <string> Set the bar(s) statustext\n"
- " -V <viwmfs cmd> Manage WMFS with vi-like command\n"
- " -S Update status script\n"
- " -h Show this page\n"
- " -i Show informations\n"
- " -v Show WMFS version\n", argv[0]);
- exit(EXIT_SUCCESS);
- break;
- case 'i':
- printf("WMFS - Window Manager From Scratch By Martin Duquesnoy\n");
- exit(EXIT_SUCCESS);
- break;
- case 'v':
- printf("WMFS version : "WMFS_VERSION"\n"
- " Compilation settings :\n"
- " - Flags : "WMFS_COMPILE_FLAGS"\n"
- " - Linked Libs : "WMFS_LINKED_LIBS"\n"
- " - On "WMFS_COMPILE_MACHINE" by "WMFS_COMPILE_BY".\n");
- exit(EXIT_SUCCESS);
- break;
- case 'S':
- update_status();
- XCloseDisplay(dpy);
- exit(EXIT_SUCCESS);
- break;
- case 'C':
- strcpy(conf.confpath, optarg);
- break;
- case 'c':
- exec_uicb_function(argv[2], ((argv[3]) ? argv[3] : NULL));
- XCloseDisplay(dpy);
- exit(EXIT_SUCCESS);
- break;
- case 's':
- if(argc > 3)
- set_statustext(atoi(optarg), argv[3]);
- else
- set_statustext(-1, optarg);
- XCloseDisplay(dpy);
- exit(EXIT_SUCCESS);
- break;
- case 'g':
- getinfo(optarg);
- XCloseDisplay(dpy);
- exit(EXIT_SUCCESS);
- break;
- case 'V':
- viwmfs(argc, argv);
- XCloseDisplay(dpy);
- exit(EXIT_SUCCESS);
- break;
- }
- }
- /* Check if WMFS can open X server */
- if(!(dpy = XOpenDisplay(NULL)))
- errx(EXIT_FAILURE, "cannot open X server.");
- /* Set signal handler */
- (void)signal(SIGTERM, &signal_handle);
- (void)signal(SIGINT, &signal_handle);
- /* Check if an other WM is already running; set the error handler */
- XSetErrorHandler(errorhandler);
- /* Let's Go ! */
- init();
- scan();
- mainloop();
- quit();
- return 0;
- }
|