File indexing completed on 2024-04-21 04:53:58

0001 /*
0002     This file is part of the KMPlayer application
0003     SPDX-FileCopyrightText: 2004 Koos Vriezen <koos.vriezen@xs4all.nl>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include <cstdio>
0009 #include <cstring>
0010 #include <cmath>
0011 #include "config-kmplayer.h"
0012 #include <dcopclient.h>
0013 #include <QCString>
0014 #include <QTimer>
0015 #include <QFile>
0016 #include <QUrl>
0017 #include <QThread>
0018 #include <QMutex>
0019 #include <QDom>
0020 #include "kmplayer_backend.h"
0021 #include "kmplayer_callback_stub.h"
0022 #include "kmplayer_callback.h"
0023 #include "xvplayer.h"
0024 #include <X11/X.h>
0025 #include <X11/Xlib.h>
0026 #include <X11/Xutil.h>
0027 #include <X11/keysym.h>
0028 #include <X11/Xatom.h>
0029 #include <X11/Xutil.h>
0030 #include <X11/extensions/XShm.h>
0031 #include <X11/extensions/Xvlib.h>
0032 
0033 
0034 static char                 configfile[2048];
0035 
0036 static Display             *display;
0037 static KXVideoPlayer       *xvapp;
0038 static KMPlayer::Callback_stub * callback;
0039 static Window               wid;
0040 static GC                   gc;
0041 static bool                 window_created = true;
0042 static bool                 wants_config;
0043 static bool                 verbose;
0044 static bool                 running;
0045 static bool                 have_freq;
0046 static bool                 xv_success;
0047 static bool                 reset_xv_autopaint_colorkey;
0048 static bool                 reset_xv_mute;
0049 static int                  xvport;
0050 static int                  xv_encoding = -1;
0051 static QString              xv_norm;
0052 static int                  xv_frequency;
0053 static int                  screen;
0054 static int                  movie_width;
0055 static int                  movie_height;
0056 static int                  current_volume;
0057 static int                  tmp_volume;
0058 static const int            start_vol_timeout = 100;
0059 static const int            inc_vol_timeout = 20;
0060 Atom xv_enc_atom;
0061 Atom xv_hue_atom;
0062 Atom xv_saturation_atom;
0063 Atom xv_brightness_atom;
0064 Atom xv_contrast_atom;
0065 Atom xv_freq_atom;
0066 Atom xv_volume_atom;
0067 Atom xv_mute_atom;
0068 Atom xv_autopaint_colorkey_atom;
0069 enum {
0070     limit_volume = 0,
0071     limit_hue, limit_contrast, limit_brightness, limit_saturation,
0072     limit_last
0073 };
0074 static struct Limit { int min; int max; } xv_limits [limit_last];
0075 static QString elmentry ("entry");
0076 static QString elmitem ("item");
0077 static QString attname ("name");
0078 static QString atttype ("type");
0079 static QString attdefault ("DEFAULT");
0080 static QString attvalue ("value");
0081 //static QString attstart ("START");
0082 //static QString attend ("END");
0083 //static QString valrange ("range");
0084 //static QString valnum ("num");
0085 //static QString valbool ("bool");
0086 //static QString valenum ("enum");
0087 //static QString valstring ("string");
0088 static QString valtree ("tree");
0089 static QByteArray config_buf;
0090 
0091 extern "C" {
0092 
0093 } // extern "C"
0094 
0095 static void putVideo () {
0096     XWindowAttributes attr;
0097     XGetWindowAttributes (display, wid, &attr);
0098     XvPutVideo (display, xvport, wid, gc, 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height);
0099 }
0100 
0101 using namespace KMPlayer;
0102 
0103 Backend::Backend ()
0104     : DCOPObject (QCString ("Backend")) {
0105 }
0106 
0107 Backend::~Backend () {}
0108 
0109 void Backend::setURL (unsigned long, QString) {
0110 }
0111 
0112 void Backend::setSubTitleURL (unsigned long, QString) {
0113 }
0114 
0115 void Backend::play (long unsigned int, int) {
0116     xvapp->play ();
0117 }
0118 
0119 void Backend::stop (unsigned long) {
0120     QTimer::singleShot (0, xvapp, SLOT (stop ()));
0121 }
0122 
0123 void Backend::pause (unsigned long) {
0124 }
0125 
0126 void Backend::seek (unsigned long, int, bool /*absolute*/) {
0127 }
0128 
0129 void Backend::hue (unsigned long, int h, bool) {
0130     if (xv_limits[limit_hue].max > xv_limits[limit_hue].min)
0131         xvapp->hue ((h + 100) * (xv_limits[limit_hue].max - xv_limits[limit_hue].min)/200 + xv_limits[limit_hue].min);
0132 }
0133 
0134 void Backend::saturation (unsigned long, int s, bool) {
0135     if (xv_limits[limit_saturation].max > xv_limits[limit_saturation].min)
0136         xvapp->saturation ((s + 100) * (xv_limits[limit_saturation].max - xv_limits[limit_saturation].min)/200 + xv_limits[limit_saturation].min);
0137 }
0138 
0139 void Backend::contrast (unsigned long, int c, bool) {
0140     if (xv_limits[limit_contrast].max > xv_limits[limit_contrast].min)
0141         xvapp->contrast ((c + 100)*(xv_limits[limit_contrast].max - xv_limits[limit_contrast].min)/200 + xv_limits[limit_contrast].min);
0142 }
0143 
0144 void Backend::brightness (unsigned long, int b, bool) {
0145     if (xv_limits[limit_brightness].max > xv_limits[limit_brightness].min)
0146         xvapp->brightness ((b + 100)*(xv_limits[limit_brightness].max - xv_limits[limit_brightness].min)/200 + xv_limits[limit_brightness].min);
0147 }
0148 
0149 void Backend::volume (unsigned long, int v, bool) {
0150     if (xv_limits[limit_volume].max > xv_limits[limit_volume].min)
0151         xvapp->volume (v*(xv_limits[limit_volume].max - xv_limits[limit_volume].min)/100 + xv_limits[limit_volume].min);
0152 }
0153 
0154 void Backend::property (unsigned long wid, QString prop, QString val) {
0155     if (prop == "frequency")
0156         xvapp->frequency (val.toInt ());
0157 }
0158 
0159 void Backend::setAudioLang (unsigned long, int, QString) {
0160 }
0161 
0162 void Backend::setSubtitle (unsigned long, int, QString) {
0163 }
0164 
0165 void Backend::quit () {
0166     delete callback;
0167     callback = 0L;
0168     if (running)
0169         stop (0);
0170     else
0171         QTimer::singleShot (0, qApp, SLOT (quit ()));
0172 }
0173 
0174 bool updateConfigEntry (const QString & name, const QString & value) {
0175     fprintf (stderr, "%s=%s\n", name.ascii (), (const char *) value.local8Bit ());
0176     return true;
0177 }
0178 
0179 void Backend::setConfig (QByteArray data) {
0180     QString err;
0181     int line, column;
0182     QDomDocument dom;
0183     if (dom.setContent (data, false, &err, &line, &column)) {
0184         if (dom.childNodes().length () == 1) {
0185             for (QDomNode node = dom.firstChild().firstChild();
0186                     !node.isNull ();
0187                     node = node.nextSibling ()) {
0188                 QDomNamedNodeMap attr = node.attributes ();
0189                 updateConfigEntry (attr.namedItem (attname).nodeValue (),
0190                                    attr.namedItem (attvalue).nodeValue ());
0191             }
0192         } else
0193             err = QString ("invalid data");
0194     }
0195     if (callback)
0196         callback->errorMessage (0, 0, err);
0197 }
0198 
0199 bool Backend::isPlaying (unsigned long) {
0200     return running;
0201 }
0202 
0203 KXVideoPlayer::KXVideoPlayer (int _argc, char ** _argv)
0204   : QApplication (_argc, _argv, false), mute_timer (0) {
0205 }
0206 
0207 void KXVideoPlayer::init () {
0208     int xpos    = 0;
0209     int ypos    = 0;
0210     int width   = 320;
0211     int height  = 200;
0212 
0213     XLockDisplay(display);
0214     if (window_created)
0215         wid = XCreateSimpleWindow(display, XDefaultRootWindow(display),
0216                 xpos, ypos, width, height, 1, 0, 0);
0217     if (!callback)
0218         QTimer::singleShot (10, this, SLOT (play ()));
0219     XSelectInput (display, wid,
0220                   (PointerMotionMask | ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask)); // | SubstructureNotifyMask));
0221     XvAdaptorInfo * ai;
0222     unsigned int adaptors;
0223     xv_success = true;
0224     QDomDocument doc;
0225     QDomElement root = doc.createElement (QString ("document"));
0226     if (XvQueryAdaptors (display, XDefaultRootWindow (display), &adaptors, &ai) == Success) {
0227         QDomElement elm = doc.createElement (elmentry);
0228         elm.setAttribute (attname, QString ("XVideo"));
0229         elm.setAttribute (atttype, valtree);
0230         for (unsigned i = 0; i < adaptors; i++) {
0231             if ((ai[i].type & XvInputMask) &&
0232                     (ai[i].type & XvVideoMask) &&
0233                     ai[i].base_id > 0) {
0234                 int port = ai[i].base_id;
0235                 fprintf (stderr, "xvport %d\n", port);
0236                 bool freq_found = false;
0237                 XvAttribute *attributes = 0L;
0238                 int nr_attr, cur_val;
0239                 attributes = XvQueryPortAttributes (display, port, &nr_attr);
0240                 if (attributes) {
0241                     for (int i = 0; i < nr_attr; i++) {
0242                         if (!strcmp (attributes[i].name, "XV_FREQ"))
0243                             freq_found = true;
0244                         Atom atom = XInternAtom (display, attributes[i].name, false);
0245                         fprintf (stderr, "%s[%d] (%d .. %d)", attributes[i].name, ( int ) atom, attributes[i].min_value, attributes[i].max_value);
0246                         if ((attributes[i].flags & XvGettable) && XvGetPortAttribute (display, port, atom, &cur_val) == Success)
0247                             fprintf (stderr, " current: %d", cur_val);
0248                         fprintf (stderr, "\n");
0249                     }
0250                     XFree(attributes);
0251                 }
0252                 if (!xvport && ((xv_frequency > 0) == freq_found)) {
0253                     fprintf (stderr, "using xvport %d\n", port);
0254                     xvport = port;
0255                 }
0256                 if (xvport == port)
0257                     have_freq = freq_found;
0258                 XvEncodingInfo * encodings = 0L;
0259                 unsigned nr_encode;
0260                 XvQueryEncodings (display, port, &nr_encode, &encodings);
0261                 if (encodings) {
0262                     QDomElement port_item = doc.createElement (QString("Port"));
0263                     port_item.setAttribute (attvalue, QString::number (port));
0264                     if (freq_found)
0265                         port_item.setAttribute (QString("FREQ"), QString("1"));
0266                     for (unsigned i = 0; i < nr_encode; i++) {
0267                         if (strcmp (encodings[i].name, "XV_IMAGE")) {
0268                             if (xvport == port && xv_encoding < 0 && !xv_norm.isEmpty () && QString (encodings[i].name).lower ().startsWith(xv_norm.lower ()))
0269                                 xv_encoding = encodings[i].encoding_id;
0270                             if (port == xvport && encodings[i].encoding_id == xv_encoding) {
0271                                 movie_width = encodings[i].width;
0272                                 movie_height = encodings[i].height;
0273                             }
0274                             QDomElement item = doc.createElement (QString ("Input"));
0275                             item.setAttribute (attvalue, QString::number (encodings[i].encoding_id));
0276                             item.setAttribute (attname, QString (encodings[i].name));
0277                             port_item.appendChild (item);
0278                             fprintf (stderr, " encoding: %d %s\n", ( int ) encodings[i].encoding_id, encodings[i].name);
0279                         }
0280                     }
0281                     elm.appendChild (port_item);
0282                     XvFreeEncodingInfo (encodings);
0283                 }
0284             }
0285         }
0286         root.appendChild (elm);
0287         XvFreeAdaptorInfo(ai);
0288     }
0289     doc.appendChild (root);
0290     QCString exp = doc.toCString ();
0291     config_buf = exp;
0292     //fprintf (stderr, "%s\n", (const char *)exp);
0293     config_buf.resize (exp.length ()); // strip terminating \0
0294 
0295     if (xvport <= 0) {
0296         fprintf (stderr, "no valid xvport found\n");
0297         xv_success = false;
0298         return;
0299     }
0300     if (window_created) {
0301         fprintf (stderr, "map %lu\n", wid);
0302         if (movie_width > 0 && movie_height > 0)
0303             XResizeWindow (display, wid, movie_width, movie_height);
0304         XMapRaised(display, wid);
0305         XSync(display, False);
0306     }
0307     XUnlockDisplay(display);
0308     if (!xv_success)
0309         fprintf (stderr, "Failed to init %d port\n", xvport);
0310 }
0311 
0312 KXVideoPlayer::~KXVideoPlayer () {
0313     if (window_created) {
0314         XLockDisplay (display);
0315         fprintf (stderr, "unmap %lu\n", wid);
0316         XUnmapWindow (display,  wid);
0317         XDestroyWindow(display,  wid);
0318         XSync (display, False);
0319         XUnlockDisplay (display);
0320     }
0321     xvapp = 0L;
0322 }
0323 
0324 void getConfigEntries (QByteArray & buf) {
0325     QDomDocument doc;
0326     QDomElement root = doc.createElement (QString ("document"));
0327     doc.appendChild (root);
0328     QCString exp = doc.toCString ();
0329     buf = exp;
0330     buf.resize (exp.length ()); // strip terminating \0
0331 }
0332 
0333 void KXVideoPlayer::play () {
0334     fprintf (stderr, "play xv://%d:%d/%d\n", xvport, xv_encoding, xv_frequency);
0335     if (!xv_success)
0336         return;
0337     if (callback && movie_width > 0 && movie_height > 0)
0338         callback->movieParams (0, 0, movie_width, movie_height, 1.0*movie_width/movie_height, QStringList (), QStringList ());
0339     XLockDisplay (display);
0340     if (!running && XvGrabPort (display, xvport, CurrentTime) == Success) {
0341         gc = XCreateGC (display, wid, 0, NULL);
0342         XvSelectPortNotify (display, xvport, 1);
0343         XvSelectVideoNotify (display, wid, 1);
0344         int nr, cur_val;
0345         if (XvGetPortAttribute (display, xvport, xv_autopaint_colorkey_atom, &cur_val) == Success && cur_val == 0) {
0346             fprintf (stderr, "XV_AUTOPAINT_COLORKEY is 0\n");
0347             XvSetPortAttribute (display, xvport, xv_autopaint_colorkey_atom, 1);
0348             reset_xv_autopaint_colorkey = true;
0349         }
0350         XvAttribute *attributes = XvQueryPortAttributes (display, xvport, &nr);
0351         if (attributes) {
0352             for (int i = 0; i < nr; i++) {
0353                 Limit * limit = 0;
0354                 Atom atom = XInternAtom (display, attributes[i].name, false);
0355                 if (atom == xv_volume_atom) {
0356                     limit = xv_limits + limit_volume;
0357                     XvGetPortAttribute (display, xvport,
0358                             xv_volume_atom, &current_volume);
0359                 } else if (atom == xv_hue_atom) {
0360                     limit = xv_limits + limit_hue;
0361                 } else if (atom == xv_saturation_atom) {
0362                     limit = xv_limits + limit_saturation;
0363                 } else if (atom == xv_brightness_atom) {
0364                     limit = xv_limits + limit_brightness;
0365                 } else if (atom == xv_contrast_atom) {
0366                     limit = xv_limits + limit_contrast;
0367                 } else
0368                     continue;
0369                 limit->min = attributes[i].min_value;
0370                 limit->max = attributes[i].max_value;
0371             }
0372             XFree (attributes);
0373         }
0374         if (xv_frequency > 0)
0375             XvSetPortAttribute (display, xvport, xv_freq_atom, int (1.0*xv_frequency/62.5));
0376         if (xv_encoding >= 0)
0377             XvSetPortAttribute (display, xvport, xv_enc_atom, xv_encoding);
0378         if (XvGetPortAttribute (display, xvport, xv_mute_atom, &cur_val) ==
0379                 Success && cur_val == 1) {
0380             fprintf (stderr, "XV_MUTE is 1\n");
0381             if (xv_limits[limit_volume].min != xv_limits[limit_volume].max) {
0382                 tmp_volume = xv_limits[limit_volume].min;
0383                 XvSetPortAttribute(display, xvport, xv_volume_atom, tmp_volume);
0384                 mute_timer = startTimer (start_vol_timeout);
0385             }
0386             XvSetPortAttribute (display, xvport, xv_mute_atom, 0);
0387             reset_xv_mute = true;
0388         }
0389         //XvGetVideo (..
0390         running = true;
0391     }
0392     if (running) {
0393         putVideo ();
0394         if (callback) {
0395             callback->playing (0);
0396             callback->statusMessage (0, (int) KMPlayer::Callback::stat_hasvideo, QString ());
0397         }
0398     }
0399     XUnlockDisplay (display);
0400 }
0401 
0402 void KXVideoPlayer::stop () {
0403     if (mute_timer) {
0404         killTimer (mute_timer);
0405         mute_timer = 0;
0406     }
0407     if (running) {
0408         running = false;
0409         XLockDisplay (display);
0410         XvStopVideo (display, xvport, wid);
0411         if (reset_xv_autopaint_colorkey) {
0412             XvSetPortAttribute (display, xvport, xv_autopaint_colorkey_atom, 0);
0413             reset_xv_autopaint_colorkey = false;
0414         }
0415         if (reset_xv_mute) {
0416             XvSetPortAttribute (display, xvport, xv_mute_atom, 1);
0417             reset_xv_mute = false;
0418         }
0419         XvUngrabPort (display, xvport, CurrentTime);
0420         XFreeGC (display, gc);
0421         XClearArea (display, wid, 0, 0, 0, 0, true);
0422         XUnlockDisplay (display);
0423     }
0424     if (callback)
0425         callback->finished (0);
0426     else
0427         QTimer::singleShot (0, qApp, SLOT (quit ()));
0428 }
0429 
0430 void KXVideoPlayer::finished () {
0431     QTimer::singleShot (10, this, SLOT (stop ()));
0432 }
0433 
0434 void KXVideoPlayer::saturation (int val) {
0435     XLockDisplay(display);
0436     XvSetPortAttribute (display, xvport, xv_saturation_atom, val);
0437     XFlush (display);
0438     XUnlockDisplay(display);
0439 }
0440 
0441 void KXVideoPlayer::hue (int val) {
0442     XLockDisplay(display);
0443     XvSetPortAttribute (display, xvport, xv_hue_atom, val);
0444     XFlush (display);
0445     XUnlockDisplay(display);
0446 }
0447 
0448 void KXVideoPlayer::contrast (int val) {
0449     XLockDisplay(display);
0450     XvSetPortAttribute (display, xvport, xv_contrast_atom, val);
0451     XFlush (display);
0452     XUnlockDisplay(display);
0453 }
0454 
0455 void KXVideoPlayer::brightness (int val) {
0456     XLockDisplay(display);
0457     XvSetPortAttribute (display, xvport, xv_brightness_atom, val);
0458     XFlush (display);
0459     XUnlockDisplay(display);
0460 }
0461 
0462 void KXVideoPlayer::volume (int val) {
0463     current_volume = val;
0464     if (mute_timer)
0465         return;
0466     XLockDisplay(display);
0467     XvSetPortAttribute (display, xvport, xv_volume_atom, val);
0468     XFlush (display);
0469     XUnlockDisplay(display);
0470 }
0471 
0472 void KXVideoPlayer::frequency (int val) {
0473     // this doesn't work, changing frequency kills audio for me
0474     if (mute_timer) {
0475         killTimer (mute_timer);
0476         mute_timer = 0;
0477     }
0478     xv_frequency = val;
0479     if (running && have_freq) {
0480         XLockDisplay(display);
0481         if (xv_limits[limit_volume].min != xv_limits[limit_volume].max) {
0482             tmp_volume = xv_limits[limit_volume].min;
0483             XvSetPortAttribute (display, xvport, xv_volume_atom, tmp_volume);
0484             mute_timer = startTimer (start_vol_timeout);
0485             XFlush (display);
0486             XvSetPortAttribute (display, xvport, xv_mute_atom, 0);
0487         }
0488         XvSetPortAttribute (display, xvport, xv_freq_atom, int (1.0*val/6.25));
0489         XFlush (display);
0490         XUnlockDisplay(display);
0491     }
0492 }
0493 
0494 void KXVideoPlayer::saveState (QSessionManager & sm) {
0495     if (callback)
0496         sm.setRestartHint (QSessionManager::RestartNever);
0497 }
0498 
0499 void KXVideoPlayer::timerEvent (QTimerEvent * e) {
0500     if (e->timerId () == mute_timer) {
0501         int step = (current_volume - xv_limits[limit_volume].min) / 20;
0502         if (step > 0 && tmp_volume == xv_limits[limit_volume].min) {
0503             killTimer (mute_timer);
0504             mute_timer = startTimer (inc_vol_timeout);
0505         }
0506         tmp_volume += step;
0507         if (tmp_volume >= current_volume || step <= 0) {
0508             tmp_volume = current_volume;
0509             killTimer (mute_timer);
0510             mute_timer = 0;
0511         }
0512         XLockDisplay(display);
0513         XvSetPortAttribute (display, xvport, xv_volume_atom, tmp_volume);
0514         XFlush (display);
0515         XUnlockDisplay(display);
0516     } else
0517         killTimer (e->timerId ());
0518 }
0519 
0520 class XEventThread : public QThread {
0521 protected:
0522     void run () {
0523         Time prev_click_time = 0;
0524         int prev_click_x = 0;
0525         int prev_click_y = 0;
0526         while (true) {
0527             XEvent   xevent;
0528             XNextEvent(display, &xevent);
0529             switch(xevent.type) {
0530                 case ClientMessage:
0531                     if (xevent.xclient.format == 8 &&
0532                             !strncmp(xevent.xclient.data.b, "quit_now", 8)) {
0533                         fprintf(stderr, "request quit\n");
0534                         return;
0535                     }
0536                     break;
0537                 case KeyPress: {
0538                     XKeyEvent  kevent;
0539                     KeySym     ksym;
0540                     char       kbuf[256];
0541                     int        len;
0542                     kevent = xevent.xkey;
0543                     XLockDisplay(display);
0544                     len = XLookupString(&kevent, kbuf, sizeof(kbuf), &ksym, NULL);
0545                     XUnlockDisplay(display);
0546                     fprintf(stderr, "keypressed 0x%x 0x%x\n", ( int ) kevent.keycode, ( int ) ksym);
0547                     switch (ksym) {
0548                         case XK_q:
0549                         case XK_Q:
0550                             xvapp->lock ();
0551                             xvapp->stop ();
0552                             xvapp->unlock ();
0553                             break;
0554                     }
0555                     break;
0556                 }
0557                 case Expose:
0558                     if(xevent.xexpose.count != 0 || xevent.xexpose.window != wid)
0559                         break;
0560                     break;
0561 
0562                 case ConfigureNotify:
0563                     if (::running)
0564                         putVideo ();
0565                     break;
0566                 case XvVideoNotify:
0567                     fprintf (stderr, "xvevent %lu\n", ((XvEvent*)&xevent)->xvvideo.reason);
0568                     break;
0569                 case ButtonPress: {
0570                     XButtonEvent *bev = (XButtonEvent *) &xevent;
0571                     int dx = prev_click_x - bev->x;
0572                     int dy = prev_click_y - bev->y;
0573                     if (bev->time - prev_click_time < 400 &&
0574                             (dx * dx + dy * dy) < 25) {
0575                         xvapp->lock ();
0576                         if (callback)
0577                             callback->toggleFullScreen (0);
0578                         xvapp->unlock ();
0579                     }
0580                     prev_click_time = bev->time;
0581                     prev_click_x = bev->x;
0582                     prev_click_y = bev->y;
0583                     break;
0584                 }
0585                 default:
0586                     if (xevent.type < LASTEvent) {
0587                         //fprintf (stderr, "event %d\n", xevent.type);
0588                     }
0589             }
0590         }
0591     }
0592 };
0593 
0594 int main(int argc, char **argv) {
0595     if (!XInitThreads ()) {
0596         fprintf (stderr, "XInitThreads () failed\n");
0597         return 1;
0598     }
0599     display = XOpenDisplay(NULL);
0600     screen  = XDefaultScreen(display);
0601 
0602     unsigned int ver, rel, req, evb, err;
0603     if (XvQueryExtension (display, &ver, &rel, &req, &evb, &err) != Success) {
0604         fprintf (stderr, "XVideo not supported on display\n");
0605         XCloseDisplay (display);
0606         return 1;
0607     }
0608     xv_enc_atom = XInternAtom (display, "XV_ENCODING", false);
0609     xv_hue_atom = XInternAtom (display, "XV_HUE", false);
0610     xv_saturation_atom = XInternAtom (display, "XV_SATURATION", false);
0611     xv_brightness_atom = XInternAtom (display, "XV_BRIGHTNESS", false);
0612     xv_contrast_atom = XInternAtom (display, "XV_CONTRAST", false);
0613     xv_freq_atom = XInternAtom (display, "XV_FREQ", false);
0614     xv_volume_atom = XInternAtom (display, "XV_VOLUME", false);
0615     xv_mute_atom = XInternAtom (display, "XV_MUTE", false);
0616     xv_autopaint_colorkey_atom = XInternAtom (display, "XV_AUTOPAINT_COLORKEY", false);
0617 
0618     xvapp = new KXVideoPlayer (argc, argv);
0619 
0620     for(int i = 1; i < argc; i++) {
0621         if (!strcmp (argv [i], "-port")) {
0622             xvport = strtol (argv [++i], 0L, 10);
0623         } else if (!strcmp (argv [i], "-wid") || !strcmp (argv [i], "-window-id")) {
0624             wid = atol (argv [++i]);
0625             window_created = false;
0626         } else if (!strcmp (argv [i], "-root")) {
0627             wid =  XDefaultRootWindow (display);
0628             window_created = false;
0629         } else if (!strcmp (argv [i], "-window")) {
0630             ;
0631         } else if (!strcmp (argv [i], "-v")) {
0632             verbose = true;
0633         } else if (!strcmp (argv [i], "-c")) {
0634             wants_config = true;
0635         } else if (!strcmp (argv [i], "-f") && i < argc - 1) {
0636             strncpy (configfile, argv [++i], sizeof (configfile));
0637             configfile[sizeof (configfile) - 1] = 0;
0638         } else if (!strcmp (argv [i], "-cb")) {
0639             QString str = argv [++i];
0640             int pos = str.find ('/');
0641             if (pos > -1) {
0642                 fprintf (stderr, "callback is %s %s\n", str.left (pos).ascii (), str.mid (pos + 1).ascii ());
0643                 callback = new KMPlayer::Callback_stub 
0644                     (str.left (pos).ascii (), str.mid (pos + 1).ascii ());
0645             }
0646         } else if (!strcmp (argv [i], "-enc")) {
0647             xv_encoding = strtol (argv [++i], 0L, 10);
0648         } else if (!strcmp (argv [i], "-norm")) {
0649             xv_norm = argv [++i];
0650         } else if (!strcmp (argv [i], "-freq")) {
0651             xv_frequency = strtol (argv [++i], 0L, 10);
0652         } else  {
0653             fprintf (stderr, "usage: %s [-port <xv port>] [-enc <encoding>] [-freq <frequency>] [-f <config file>] [-v] [(-wid|-window-id) <window>] [(-root|-window)] [-cb <DCOP callback name> [-c]]\n", argv[0]);
0654             delete xvapp;
0655             return 1;
0656         }
0657     }
0658 
0659     DCOPClient dcopclient;
0660     dcopclient.registerAs ("kxvideoplayer");
0661     Backend player;
0662 
0663     XEventThread * eventThread = new XEventThread;
0664     eventThread->start ();
0665 
0666     xvapp->init ();
0667 
0668     if (callback)
0669         callback->started (dcopclient.appId (), config_buf);
0670 
0671     xvapp->exec ();
0672 
0673     XLockDisplay(display);
0674     XClientMessageEvent ev = {
0675         ClientMessage, 0, true, display, wid, 
0676         XInternAtom (display, "XVIDEO", false), 8, {"quit_now"}
0677     };
0678     XSendEvent (display, wid, false, StructureNotifyMask, (XEvent *) & ev);
0679     XFlush (display);
0680     XUnlockDisplay(display);
0681     eventThread->wait (500);
0682     delete eventThread;
0683 
0684     xvapp->stop ();
0685     delete xvapp;
0686 
0687     fprintf (stderr, "closing display\n");
0688     XCloseDisplay (display);
0689     fprintf (stderr, "done\n");
0690     return 0;
0691 }
0692 
0693 #include "xvplayer.moc"
0694 
0695 #include "moc_xvplayer.cpp"