mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 09:23:03 -04:00
twirling icon on X11 too
This commit is contained in:
parent
cbc1842899
commit
7a11d70f14
@ -16,6 +16,7 @@
|
||||
#define PLUGIN_GET_X11_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "p3d_plugin_config.h"
|
||||
|
||||
#ifdef HAVE_X11
|
||||
// This header file is designed to help work around some of the
|
||||
@ -27,18 +28,12 @@
|
||||
// should include this file instead of including the X11 headers
|
||||
// directly.
|
||||
|
||||
#define Display X11_Display
|
||||
#define Window X11_Window
|
||||
#define Cursor X11_Cursor
|
||||
#define Connection X11_Connection
|
||||
#include "pre_x11_include.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#undef Display
|
||||
#undef Window
|
||||
#undef Cursor
|
||||
#undef Connection
|
||||
#include "post_x11_include.h"
|
||||
|
||||
#endif // HAVE_X11
|
||||
|
||||
|
@ -37,10 +37,10 @@
|
||||
#include <sys/time.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#if defined(HAVE_GTK) && defined(HAVE_X11)
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#endif // HAVE_GTK
|
||||
#ifdef HAVE_X11
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#endif // HAVE_X11
|
||||
|
||||
|
||||
PPInstance::FileDatas PPInstance::_file_datas;
|
||||
@ -131,6 +131,13 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16_t mode,
|
||||
_use_xembed = false;
|
||||
_got_window = false;
|
||||
_python_window_open = false;
|
||||
#ifdef HAVE_X11
|
||||
_twirl_subprocess_pid = -1;
|
||||
#ifdef HAVE_GTK
|
||||
_plug = NULL;
|
||||
#endif // HAVE_GTK
|
||||
#endif // HAVE_X11
|
||||
|
||||
#ifdef _WIN32
|
||||
_hwnd = NULL;
|
||||
_bg_brush = NULL;
|
||||
@ -349,6 +356,23 @@ set_window(NPWindow *window) {
|
||||
_window = *window;
|
||||
_got_window = true;
|
||||
|
||||
#ifdef HAVE_X11
|
||||
#ifdef HAVE_GTK
|
||||
if (_use_xembed) {
|
||||
// Create a GtkPlug to bind to the XEmbed socket.
|
||||
_plug = gtk_plug_new((GdkNativeWindow)_window.window);
|
||||
gtk_widget_show(_plug);
|
||||
|
||||
nout << "original XID is " << _window.window << ", created X11 window "
|
||||
<< GDK_DRAWABLE_XID(_plug->window) << "\n";
|
||||
}
|
||||
#endif // HAVE_GTK
|
||||
|
||||
if (!_failed && _p3d_inst == NULL) {
|
||||
x11_start_twirl_subprocess();
|
||||
}
|
||||
#endif // HAVE_X11
|
||||
|
||||
if (!_failed) {
|
||||
if (_p3d_inst == NULL) {
|
||||
create_instance();
|
||||
@ -1752,6 +1776,10 @@ create_instance() {
|
||||
}
|
||||
#endif // __APPLE__
|
||||
|
||||
#ifdef HAVE_X11
|
||||
x11_stop_twirl_subprocess();
|
||||
#endif // HAVE_X11
|
||||
|
||||
// In the Windows case, we let the timer keep running, because it
|
||||
// also checks for wayward messages.
|
||||
|
||||
@ -1853,25 +1881,19 @@ send_window() {
|
||||
// If we're using the XEmbed model, we've actually received an
|
||||
// XID for a GtkSocket.
|
||||
#ifdef HAVE_GTK
|
||||
// Create the appropriate GtkPlug.
|
||||
GtkWidget *plug = gtk_plug_new((GdkNativeWindow)_window.window);
|
||||
gtk_widget_show(plug);
|
||||
|
||||
// Now just get the X11 Window pointer to pass down to Panda,
|
||||
// since that's what it will be expecting. (Hmm, it would be
|
||||
// nice to pass the XID object and use this system in general
|
||||
// within Panda, but that's for the future, I think.)
|
||||
nout << "original XID is " << _window.window << ", created X11 window "
|
||||
<< GDK_DRAWABLE_XID(plug->window) << "\n";
|
||||
// If we're using XEmbed, pass the X11 Window pointer of our
|
||||
// plug down to Panda. (Hmm, it would be nice to pass the XID
|
||||
// object and use this system in general within Panda, but
|
||||
// that's for the future, I think.)
|
||||
assert(_plug != NULL);
|
||||
parent_window._window_handle_type = P3D_WHT_x11_window;
|
||||
parent_window._handle._x11_window._xwindow = (unsigned long)GDK_DRAWABLE_XID(plug->window);
|
||||
parent_window._handle._x11_window._xwindow = GDK_DRAWABLE_XID(_plug->window);
|
||||
#endif // HAVE_GTK
|
||||
} else {
|
||||
// If we're not using XEmbed, this is just a standard X11 Window
|
||||
// pointer. We make it an 'unsigned long' instead of 'Window'
|
||||
// to avoid nppanda3d.so getting a dependency on X11.
|
||||
// pointer.
|
||||
parent_window._window_handle_type = P3D_WHT_x11_window;
|
||||
parent_window._handle._x11_window._xwindow = (unsigned long)(_window.window);
|
||||
parent_window._handle._x11_window._xwindow = (X11_Window)(_window.window);
|
||||
}
|
||||
x = 0;
|
||||
y = 0;
|
||||
@ -1961,8 +1983,19 @@ cleanup_window() {
|
||||
_twirl_bitmaps[step] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#ifdef HAVE_X11
|
||||
x11_stop_twirl_subprocess();
|
||||
|
||||
#ifdef HAVE_GTK
|
||||
if (_plug != NULL) {
|
||||
gtk_widget_destroy(_plug);
|
||||
_plug = NULL;
|
||||
}
|
||||
#endif // HAVE_GTK
|
||||
#endif // HAVE_X11
|
||||
|
||||
_got_window = false;
|
||||
}
|
||||
}
|
||||
@ -2795,6 +2828,235 @@ twirl_timer_callback() {
|
||||
}
|
||||
#endif // __APPLE__
|
||||
|
||||
#ifdef HAVE_X11
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PPInstance::x11_start_twirl_subprocess
|
||||
// Access: Public
|
||||
// Description: Spawns a separate process to twirl the loading icon
|
||||
// in the X11 browser window.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PPInstance::
|
||||
x11_start_twirl_subprocess() {
|
||||
assert(_twirl_subprocess_pid == -1);
|
||||
|
||||
// Fork and exec.
|
||||
pid_t child = fork();
|
||||
if (child < 0) {
|
||||
perror("fork");
|
||||
return;
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
// Here we are in the child process.
|
||||
x11_twirl_subprocess_run();
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
// In the parent process.
|
||||
_twirl_subprocess_pid = child;
|
||||
}
|
||||
#endif // HAVE_X11
|
||||
|
||||
#ifdef HAVE_X11
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PPInstance::x11_stop_twirl_subprocess
|
||||
// Access: Public
|
||||
// Description: Kills the twirl process that was started earlier.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PPInstance::
|
||||
x11_stop_twirl_subprocess() {
|
||||
if (_twirl_subprocess_pid == -1) {
|
||||
// Already stopped.
|
||||
return;
|
||||
}
|
||||
|
||||
kill(_twirl_subprocess_pid, SIGKILL);
|
||||
|
||||
int status;
|
||||
pid_t result = waitpid(_twirl_subprocess_pid, &status, 0);
|
||||
|
||||
nout << "Twirl window process has successfully stopped.\n";
|
||||
if (WIFEXITED(status)) {
|
||||
nout << " exited normally, status = "
|
||||
<< WEXITSTATUS(status) << "\n";
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
nout << " signalled by " << WTERMSIG(status) << ", core = "
|
||||
<< WCOREDUMP(status) << "\n";
|
||||
} else if (WIFSTOPPED(status)) {
|
||||
nout << " stopped by " << WSTOPSIG(status) << "\n";
|
||||
}
|
||||
}
|
||||
#endif // HAVE_X11
|
||||
|
||||
#ifdef HAVE_X11
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PPInstance::x11_twirl_subprocess_run
|
||||
// Access: Public
|
||||
// Description: The code that is run within a subprocess. This code
|
||||
// is responsible for twirling the loading icon
|
||||
// endlessly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PPInstance::
|
||||
x11_twirl_subprocess_run() {
|
||||
// Since everything within this function happens within a subprocess
|
||||
// that will just exit, we can be a little sloppy with our resource
|
||||
// allocation. It is all done directly within this function, and we
|
||||
// don't need to worry about freeing stuff.
|
||||
|
||||
// First, sleep for 0.5 seconds, so we don't start twirling right
|
||||
// away (to avoid distracting the user unnecessarily).
|
||||
|
||||
struct timespec req;
|
||||
req.tv_sec = 0;
|
||||
req.tv_nsec = 500000000; // 500 ms
|
||||
nanosleep(&req, NULL);
|
||||
|
||||
// We haven't been killed yet, so the plugin is still loading.
|
||||
// Start twirling.
|
||||
|
||||
// First, embed a window.
|
||||
X11_Display *display = XOpenDisplay(NULL);
|
||||
assert(display != NULL);
|
||||
int screen = DefaultScreen(display);
|
||||
|
||||
int depth = DefaultDepth(display, screen);
|
||||
Visual *dvisual = DefaultVisual(display, screen);
|
||||
|
||||
long event_mask = ExposureMask;
|
||||
|
||||
// Allocate the foreground and background colors.
|
||||
Colormap colormap = DefaultColormap(display, screen);
|
||||
|
||||
XColor fg;
|
||||
fg.red = _fgcolor_r * 0x101;
|
||||
fg.green = _fgcolor_g * 0x101;
|
||||
fg.blue = _fgcolor_b * 0x101;
|
||||
fg.flags = DoRed | DoGreen | DoBlue;
|
||||
unsigned long fg_pixel = -1;
|
||||
if (XAllocColor(display, colormap, &fg)) {
|
||||
fg_pixel = fg.pixel;
|
||||
}
|
||||
|
||||
XColor bg;
|
||||
bg.red = _bgcolor_r * 0x101;
|
||||
bg.green = _bgcolor_g * 0x101;
|
||||
bg.blue = _bgcolor_b * 0x101;
|
||||
bg.flags = DoRed | DoGreen | DoBlue;
|
||||
unsigned long bg_pixel = -1;
|
||||
if (XAllocColor(display, colormap, &bg)) {
|
||||
bg_pixel = bg.pixel;
|
||||
}
|
||||
|
||||
// Initialize window attributes
|
||||
XSetWindowAttributes wa;
|
||||
wa.background_pixel = XWhitePixel(display, screen);
|
||||
if (bg_pixel != -1) {
|
||||
wa.background_pixel = bg_pixel;
|
||||
}
|
||||
wa.border_pixel = 0;
|
||||
wa.event_mask = event_mask;
|
||||
|
||||
unsigned long attrib_mask = CWBackPixel | CWBorderPixel | CWEventMask;
|
||||
|
||||
X11_Window parent = GDK_DRAWABLE_XID(_plug->window);
|
||||
X11_Window window = XCreateWindow
|
||||
(display, parent, 0, 0, _window.width, _window.height,
|
||||
0, depth, InputOutput, dvisual, attrib_mask, &wa);
|
||||
XMapWindow(display, window);
|
||||
|
||||
// Create a graphics context.
|
||||
XGCValues gcval;
|
||||
gcval.function = GXcopy;
|
||||
gcval.plane_mask = AllPlanes;
|
||||
gcval.foreground = BlackPixel(display, screen);
|
||||
if (fg_pixel != -1) {
|
||||
gcval.foreground = fg_pixel;
|
||||
}
|
||||
gcval.background = WhitePixel(display, screen);
|
||||
if (bg_pixel != -1) {
|
||||
gcval.background = bg_pixel;
|
||||
}
|
||||
GC graphics_context = XCreateGC(display, window,
|
||||
GCFunction | GCPlaneMask | GCForeground | GCBackground, &gcval);
|
||||
|
||||
// Load up the twirling images.
|
||||
XImage *images[twirl_num_steps];
|
||||
double r_ratio = dvisual->red_mask / 255.0;
|
||||
double g_ratio = dvisual->green_mask / 255.0;
|
||||
double b_ratio = dvisual->blue_mask / 255.0;
|
||||
|
||||
static const size_t twirl_size = twirl_width * twirl_height;
|
||||
unsigned char twirl_data[twirl_size * 3];
|
||||
|
||||
for (int step = 0; step < twirl_num_steps; ++step) {
|
||||
get_twirl_data(twirl_data, twirl_size, step,
|
||||
_fgcolor_r, _fgcolor_g, _fgcolor_b,
|
||||
_bgcolor_r, _bgcolor_g, _bgcolor_b);
|
||||
uint32_t *new_data = new uint32_t[twirl_size];
|
||||
int j = 0;
|
||||
for (int i = 0; i < twirl_size * 3; i += 3) {
|
||||
unsigned int r, g, b;
|
||||
r = (unsigned int)(twirl_data[i+0] * r_ratio);
|
||||
g = (unsigned int)(twirl_data[i+1] * g_ratio);
|
||||
b = (unsigned int)(twirl_data[i+2] * b_ratio);
|
||||
new_data[j++] = ((r & dvisual->red_mask) |
|
||||
(g & dvisual->green_mask) |
|
||||
(b & dvisual->blue_mask));
|
||||
}
|
||||
|
||||
// Now load the image.
|
||||
images[step] = XCreateImage(display, CopyFromParent, DefaultDepth(display, screen),
|
||||
ZPixmap, 0, (char *)new_data, twirl_width, twirl_height, 32, 0);
|
||||
}
|
||||
|
||||
// Now twirl indefinitely, until our parent process kills us.
|
||||
bool needs_redraw = true;
|
||||
int last_step = -1;
|
||||
while (true) {
|
||||
// First, scan for X events.
|
||||
XEvent event;
|
||||
while (XCheckWindowEvent(display, window, ~0, &event)) {
|
||||
switch (event.type) {
|
||||
case Expose:
|
||||
case GraphicsExpose:
|
||||
needs_redraw = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// We should probably track the resize event, but this window
|
||||
// will be short-lived (and probably won't have an opportunity
|
||||
// to resize anyway) so we don't bother.
|
||||
}
|
||||
|
||||
// What step are we on now?
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, (struct timezone *)NULL);
|
||||
double now = (double)(tv.tv_sec - _init_sec) + (double)(tv.tv_usec - _init_usec) / 1000000.0;
|
||||
int step = ((int)(now * 10.0)) % twirl_num_steps;
|
||||
if (step != last_step) {
|
||||
needs_redraw = true;
|
||||
}
|
||||
|
||||
if (needs_redraw) {
|
||||
XClearWindow(display, window);
|
||||
int xo = (_window.width - twirl_width) / 2;
|
||||
int yo = (_window.height - twirl_height) / 2;
|
||||
XPutImage(display, window, graphics_context, images[step], 0, 0,
|
||||
xo, yo, twirl_width, twirl_height);
|
||||
|
||||
XFlush(display);
|
||||
needs_redraw = false;
|
||||
last_step = step;
|
||||
}
|
||||
|
||||
struct timespec req;
|
||||
req.tv_sec = 0;
|
||||
req.tv_nsec = 100000000; // 100 ms
|
||||
nanosleep(&req, NULL);
|
||||
}
|
||||
}
|
||||
#endif // HAVE_X11
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PPInstance::StreamingFileData::Constructor
|
||||
// Access: Public
|
||||
|
@ -20,6 +20,15 @@
|
||||
#include "get_tinyxml.h"
|
||||
#include "p3d_lock.h"
|
||||
#include "get_twirl_data.h"
|
||||
#include "p3d_plugin_config.h"
|
||||
#include "plugin_get_x11.h"
|
||||
|
||||
#if defined(HAVE_X11) && defined(HAVE_GTK)
|
||||
#include "pre_x11_include.h"
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include "post_x11_include.h"
|
||||
#endif // HAVE_X11 && HAVE_GTK
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -140,6 +149,12 @@ private:
|
||||
void twirl_timer_callback();
|
||||
#endif // __APPLE__
|
||||
|
||||
#ifdef HAVE_X11
|
||||
void x11_start_twirl_subprocess();
|
||||
void x11_stop_twirl_subprocess();
|
||||
void x11_twirl_subprocess_run();
|
||||
#endif // HAVE_X11
|
||||
|
||||
private:
|
||||
NPP _npp_instance;
|
||||
unsigned int _npp_mode;
|
||||
@ -238,6 +253,10 @@ private:
|
||||
bool _use_xembed;
|
||||
bool _got_window;
|
||||
NPWindow _window;
|
||||
#if defined(HAVE_X11) && defined(HAVE_GTK)
|
||||
GtkWidget *_plug;
|
||||
#endif // HAVE_X11 && HAVE_GTK
|
||||
|
||||
#ifdef _WIN32
|
||||
LONG_PTR _orig_window_proc;
|
||||
HWND _hwnd;
|
||||
@ -266,6 +285,10 @@ private:
|
||||
bool _got_twirl_images;
|
||||
#endif // MACOSX_HAS_EVENT_MODELS
|
||||
|
||||
#ifdef HAVE_X11
|
||||
pid_t _twirl_subprocess_pid;
|
||||
#endif // HAVE_X11
|
||||
|
||||
#ifndef _WIN32
|
||||
long _init_sec;
|
||||
long _init_usec;
|
||||
|
Loading…
x
Reference in New Issue
Block a user